I have little problem with viewPager. I have ViewPager with 4 frgaments which displayed RoundedImageView. The RoundedImageView has a rounded corners. When I was swiped from right to left then a corners is not rounded. That look like this:
I set white rounded backgorund for viewpager. When I not displayed a RoundedImageView(is hide) then all is ok and I have always rounded background in view pager.
I tried set clipChildren and I failed. I don't have idea to resolve my problem.
[EDIT:]
I have another problem with RoundedClipingLayout: W/OpenGLRenderer﹕ Bitmap too large to be uploaded into a texture (1726620832x0, max=4096x4096)
I use this solution. If somebody want to check or use:
public class RoundClippingLinearLayout extends LinearLayout {
private RectF rect;
private int mCornerRadius = 10;
public RoundClippingLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
onInit();
}
public RoundClippingLinearLayout(Context context) {
super(context);
onInit();
}
protected void onInit() {
mCornerRadius = getResources().getDimensionPixelOffset(R.dimen.radius);
setWillNotDraw(false);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w != oldw && h != oldh) {
rect = new RectF(0, 0, w, h);
}
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.setDrawFilter(new PaintFlagsDrawFilter(1, Paint.ANTI_ALIAS_FLAG));
Path clipPath = new Path();
clipPath.addRoundRect(rect, mCornerRadius, mCornerRadius, Path.Direction.CW);
canvas.clipPath(clipPath);
super.dispatchDraw(canvas);
}
}
Related
I am trying to set the Width and Height for a customview on which I use Canvas to draw.
Have noticed that onDraw() always sets to a default width and height, and not take the values as specified in layout xml or set using the onMeasure method.
Could some one help me where I am going wrong.
Thanks
#Override
protected void onMeasure(final int widthMeasureSpec,
final int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());
}
you can use this code
public class CustomView extends View{
private Paint paint;
private int w;
private int h;
public CustomView(Context context, AttributeSet attr) {
super(context, attr);
paint = new Paint();
paint.setTextAlign(Align.CENTER);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
this.w = w;
this.h = h;
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
canvas.drawText("TEST", w/2, h/2, paint);
}
}
I've been trying to draw a rainbow colored ring in android using the following code:
public void init(){
ringPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
ringPaint.setStyle(Paint.Style.STROKE);
ringPaint.setStrokeWidth(8f);
ringPaint.setShader(new SweepGradient(0, 0, COLORS2, null));
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawCircle(getWidth()/2f,getHeight()/2f ,getHeight()/2f - 16f,ringPaint);
}
the value for COLOR2 is the following:
final int[] COLORS2 = new int[]{Color.parseColor("#33004c"), Color.parseColor("#4600d2"),
Color.parseColor("#0000ff"), Color.parseColor("#0099ff"),
Color.parseColor("#00eeff"),Color.parseColor("#00FF7F"),
Color.parseColor("#48FF00"),Color.parseColor("#B6FF00"),
Color.parseColor("#FFD700"),Color.parseColor("#ff9500"),
Color.parseColor("#FF6200"),Color.parseColor("#FF0000"),
Color.parseColor("#33004c")};
The problem is that I'm only getting a subset of the colors, maybe 3 or 4 of the distinct colors in the array and I'm not entirely sure why, can anyone offer some suggestion as to why this is the case?
you should specify center of view instead of 0,0 when create SweepGradient
look at example please
public class CustomView extends View {
private Paint ringPaint;
public CustomView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public void init() {
ringPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
ringPaint.setStyle(Paint.Style.STROKE);
ringPaint.setStrokeWidth(8f);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
ringPaint.setShader(new SweepGradient(getWidth() / 2, getHeight() / 2, COLORS2, null));
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, getHeight() / 2f - 16f, ringPaint);
}
}
I'm trying to achieve a visual effect, that if I could make would look awesome! The login of the app that I'm doing looks like this:
Keep in mind that the image on the background is an animation, that makes a slightly transition from that image to another.
What I want is make the title of the app "Akrasia" be transparent, but transparent meaning that you can see the image in background through the title letters, this means that in some way I must override the onDraw method of the RelativeLayout that contains this form. I tried to do that, but the only thing that I got was errors. Maybe I'm wrong trying to override the onDraw method in boths, the TextView and the RelativeLayout, maybe there's an easiest way to do it. What do you think? Or maybe is impossible to achive this effect?
UPDATE:
This is how it should look like.
Also I tried to make a custom view extending from TextView wich has a method setBackgroundView wich stores a view instance into a field. Later on the onDraw method and I managed to get the bitmap from the background image. But I don't know how draw it using canvas.
UPDATE:
I make it work! Now I only need change that blue-like background by the drawable of the background.
The view:
final public class SeeThroughTextView extends TextView
{
Bitmap mMaskBitmap;
Canvas mMaskCanvas;
Paint mPaint;
Drawable mBackground;
Bitmap mBackgroundBitmap;
Canvas mBackgroundCanvas;
boolean mSetBoundsOnSizeAvailable = false;
public SeeThroughTextView(Context context)
{
super(context);
init();
}
private void init() {
mPaint = new Paint();
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
}
public SeeThroughTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SeeThroughTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
#Override
#Deprecated
public void setBackgroundDrawable(Drawable bg)
{
mBackground = bg;
int w = bg.getIntrinsicWidth();
int h = bg.getIntrinsicHeight();
// Drawable has no dimensions, retrieve View's dimensions
if (w == -1 || h == -1)
{
w = getWidth();
h = getHeight();
}
// Layout has not run
if (w == 0 || h == 0)
{
mSetBoundsOnSizeAvailable = true;
return;
}
mBackground.setBounds(0, 0, w, h);
invalidate();
}
#Override
public void setBackgroundColor(int color)
{
setBackgroundDrawable(new ColorDrawable(color));
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
mBackgroundBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mBackgroundCanvas = new Canvas(mBackgroundBitmap);
mMaskBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mMaskCanvas = new Canvas(mMaskBitmap);
if (mSetBoundsOnSizeAvailable)
{
mBackground.setBounds(0, 0, w, h);
mSetBoundsOnSizeAvailable = false;
}
}
#Override
protected void onDraw(Canvas canvas)
{
// Draw background
mBackground.draw(mBackgroundCanvas);
// Draw mask
mMaskCanvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
super.onDraw(mMaskCanvas);
mBackgroundCanvas.drawBitmap(mMaskBitmap, 0.f, 0.f, mPaint);
canvas.drawBitmap(mBackgroundBitmap, 0.f, 0.f, null);
}
}
And in my fragment I have this because the animation in the background:
vBackground.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
vTitle.setBackgroundDrawable(new BitmapDrawable(vBackground.getDrawingCache()));
vTitle.invalidate();
}
});
Nailed!
The view:
final public class SeeThroughTextView extends TextView
{
Bitmap mMaskBitmap;
Canvas mMaskCanvas;
Paint mPaint;
Drawable mBackground;
Bitmap mBackgroundBitmap;
Canvas mBackgroundCanvas;
boolean mSetBoundsOnSizeAvailable = false;
public SeeThroughTextView(Context context)
{
super(context);
init();
}
private void init() {
Typeface myTypeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/gillsans.ttf");
setTypeface(myTypeface);
mPaint = new Paint();
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
}
public SeeThroughTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SeeThroughTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
#Override
#Deprecated
public void setBackgroundDrawable(Drawable bg)
{
mBackground = bg;
int w = bg.getIntrinsicWidth();
int h = bg.getIntrinsicHeight();
// Drawable has no dimensions, retrieve View's dimensions
if (w == -1 || h == -1)
{
w = getWidth();
h = getHeight();
}
// Layout has not run
if (w == 0 || h == 0)
{
mSetBoundsOnSizeAvailable = true;
return;
}
mBackground.setBounds(0, 0, w, h);
invalidate();
}
#Override
public void setBackgroundColor(int color)
{
setBackgroundDrawable(new ColorDrawable(color));
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
mBackgroundBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mBackgroundCanvas = new Canvas(mBackgroundBitmap);
mMaskBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mMaskCanvas = new Canvas(mMaskBitmap);
if (mSetBoundsOnSizeAvailable)
{
mBackground.setBounds(0, 0, w, h);
mSetBoundsOnSizeAvailable = false;
}
}
#Override
protected void onDraw(Canvas canvas)
{
// Draw background
mBackground.draw(mBackgroundCanvas);
// Draw mask
mMaskCanvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
super.onDraw(mMaskCanvas);
mBackgroundCanvas.drawBitmap(mMaskBitmap, 0.f, 0.f, mPaint);
canvas.drawBitmap(mBackgroundBitmap, 0.f, 0.f, null);
}
}
In my fragment:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
vLoginBtn = (Button) view.findViewById(R.id.btn_login);
vRegistrationBtn = (Button) view.findViewById(R.id.btn_registration);
vForgotBtn = (Button) view.findViewById(R.id.btn_forgot);
vBackground = (KenBurnsView) view.findViewById(R.id.login_background);
vTitle = (SeeThroughTextView) view.findViewById(R.id.txt_view_login_title);
vBackground.setResourceUrls(
"http://www.youwall.com/papel/peaceful_place_wallpaper_4f3f3.jpg",
"http://www.fwallpaper.net/wallpapers/P/E/Peaceful-Scenary_1920x1200.jpg",
"http://p1.pichost.me/i/39/1620902.jpg"
);
vBackground.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
vTitle.setBackgroundDrawable(getResources().getDrawable(R.drawable.drawable_background_login_top));
vTitle.invalidate();
vBackground.removeOnLayoutChangeListener(this);
}
});
}
The drawables are just two shapes, one with the top-left corner and top-right corner with radius 10dp and the another one with the radius in the bottoms.
The custom TextView with the top drawable shape is alligned above the RelativeLayout wich contains the EditTexts.
No much rocket science. Thanks a lot to #Klotor for suggesting the idea!
Specify a new color in your res/values/colors.xml file (create one if it doesn't exist), the file might look like:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ltGray">#33999999</color>
</resources>
where the first two numbers are transparency (00 - fully transparent, FF - fully opaque).
Then simply set the text color of desired TextView to #color/ltGray in the xml of that layout, or go
tvTitle.setTextColor(getResources().getColor(R.color.ltGray))
after instatiating the TextView.
I am trying to do something very simple (see above). I want all of the pixels of a canvas to be a solid color, except for the the pixels that fill a centered circle. I have read hundreds stack overflow post on this subject and have tried hundreds of things including setting the PorterDuff.Mode. Here is my current onDraw() of MyView extends View:
protected void onDraw(Canvas canvas) {
int w = canvas.getWidth();
int h = canvas.getHeight();
Paint framePaint = new Paint();
framePaint.setStyle(Paint.Style.FILL);
framePaint.setColor(Color.BLUE);
canvas.drawRect(0, 0, w, h, framePaint);
Paint transparentPaint = new Paint();
transparentPaint.setColor(Color.TRANSPARENT);
transparentPaint.setAntiAlias(true);
canvas.drawCircle(w / 2, h / 2, (w + h) / 4, transparentPaint);
}
Am I misunderstanding something, why cant I paint over an existing pixel with transparent paint. When I do this the pixel stays the same. When I use PorterDuff, the pixel turns black. Please help.
Try this:
public class TransparentCircle extends View {
Bitmap bm;
Canvas cv;
Paint eraser;
public TransparentCircle(Context context) {
super(context);
Init();
}
public TransparentCircle(Context context, AttributeSet attrs) {
super(context, attrs);
Init();
}
public TransparentCircle(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
Init();
}
private void Init(){
eraser = new Paint();
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
eraser.setAntiAlias(true);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (w != oldw || h != oldh) {
bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
cv = new Canvas(bm);
}
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
int w = getWidth();
int h = getHeight();
int radius = w > h ? h / 2 : w / 2;
bm.eraseColor(Color.TRANSPARENT);
cv.drawColor(Color.BLUE);
cv.drawCircle(w / 2, h / 2, radius, eraser);
canvas.drawBitmap(bm, 0, 0, null);
super.onDraw(canvas);
}
}
I have this class that extends View:
public class DrawingPanel extends View {
private Bitmap toDisk;
private int w;
private int h;
public DrawingPanel(Context context, AttributeSet attrs) {
super(context, attrs);
System.out.println("Drawing");
p0 = new Paint();
p0.setStyle(Style.STROKE);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
...
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
this.w = w;
this.h = h;
toDisk = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
public void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
canvas.drawPath(path0, p0);
canvas.setBitmap(toDisk);
}
}
I use this class as a child view in a layout. In the Graphical view of Eclipse all things are OK, and all views are visible, but in emulator my class (DrawingPanel) hides other views that are below it. When I remove this line:
canvas.setBitmap(toDisk);
all views will be visible again. And another strange thing: when I put that line in the first line of onDraw method like this:
#Override
public void onDraw(Canvas canvas) {
canvas.setBitmap(toDisk);
canvas.drawColor(Color.WHITE);
canvas.drawPath(path0, p0);
}
my DrawingPanel and other views that are below it will be invisible. How can I solve this problem?
My purpose is to save what user draws on canvas.
You misunderstand setBitmap. It sets a bitmap for you to send new draw commands to INSTEAD OF the screen. It does not draw the previous commands to a bitmap. To do that, you'd want to do this:
Canvas diskCanvas = new Canvas(toDisk);
//Send all draw commands to this canvas
screenCanvas.drawBitmap(toDisk, new Matrix(), new Paint());
Note that this will only save the bitmap to memory. To save to disk, you need to save it to a file. Do NOT do that in onDraw, its a slow operation.