I'm trying to use vector drawables to draw into canvas. Everything is fine and dandy till I rotate the canvas object by 90 or 270 degrees. Closer I get to 90 or 270 degrees, more blurry the drawable shown in canvas appears. Finally at 90 or 270 degrees, the vector drawable on canvas disappears completely. Is there some sort of fix or workaround for this? Or should I approach drawing into canvas with svg's with some other library? Thanks!
Here's the code:
public class CanvasView extends View {
private static final String TAG = "CanvasView";
private VectorDrawableCompat vectorDrawableCompat;
private int angle;
public CanvasView(Context context) {
super(context);
init();
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
vectorDrawableCompat = VectorDrawableCompat.create(getResources(),
R.drawable.ic_android_black_24dp, null);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
vectorDrawableCompat.setBounds((getWidth()/2) - 50, (getHeight()/2) - 50, (getWidth()/2) + 50, (getHeight()/2) + 50);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.rotate(angle, getWidth()/2, getHeight()/2);
vectorDrawableCompat.draw(canvas);
canvas.restore();
}
public void setAngle(int angle){
Log.i(TAG, "setAngle: " + angle);
this.angle = angle;
invalidate();
}
}
Here's the project: https://github.com/danskiess/VectorTest
This has been fixed in the android framework.
https://code.google.com/p/android/issues/detail?id=192413
One possible workaround for this rotation case could be just draw the VectorDrawable into a Bitmap, then rotate the bitmap.
Related
rectangles
I already drew the left rounded rectangle. I need to insert some lines horizontally for it to become a striped rectangle. How can I achieve this?
I already tried to use path and draw a line. But nothing worked how it was supposed to. Can someone help me?
Here's a sample code for drawing a striped rectangle in Android Canvas:
public class StripeRectView extends View {
private Paint mPaint;
private int mStripeWidth = 10;
private int mStripeHeight = 10;
public StripeRectView(Context context) {
super(context);
init();
}
public StripeRectView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public StripeRectView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.FILL);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int x = 0;
int y = 0;
while (y <= getHeight()) {
canvas.drawRect(x, y, x + mStripeWidth, y + mStripeHeight, mPaint);
x += mStripeWidth * 2;
if (x > getWidth()) {
x = 0;
y += mStripeHeight * 2;
}
}
}
}
the Canvas is used to draw rectangles, with alternating stripes of width mStripeWidth and height mStripeHeight until the entire height of the View is filled. You can modify it according to your needs.
I want to make a circular suface view (porthole effect). Surface view is inside a Frame layout. I want to make a custom view that i can add to Frame layout on top of surface view and mask whole Frame layout to produce porthole effect so that surface view will be shown as circle.
I searched and a lot for answer on Web and Stackoverflow but failed.
Then i saw this question and i tried this custom view to mask frame layout(and hence surfaceview) but i am not getting the desired result.
What i want is a custom view that can take height and width of it's parent (parent is square in shape) and make a transparent circle at it's center touching all four sides at middle of the boundaries, rest(view - circle) of the view will be of color that i can set.
public class FocusView extends View {
private Paint mTransparentPaint;
private Paint mSemiBlackPaint;
private Path mPath = new Path();
public static float radius , xCor , yCor;
public FocusView(Context context) {
super(context);
initPaints();
}
public FocusView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaints();
}
public FocusView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaints();
}
private void initPaints() {
mTransparentPaint = new Paint();
mTransparentPaint.setColor(Color.GREEN);
mTransparentPaint.setStrokeWidth(10);
mSemiBlackPaint = new Paint();
mSemiBlackPaint.setColor(Color.TRANSPARENT);
mSemiBlackPaint.setStrokeWidth(10);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.reset();
mPath.addCircle(xCor,yCor,radius, Path.Direction.CW);
mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD);
canvas.drawCircle(xCor,yCor,radius, mTransparentPaint);
canvas.drawPath(mPath, mSemiBlackPaint);
canvas.clipPath(mPath);
canvas.drawColor(Color.parseColor("#FFFFFF")); //A6000000
}
}
Please if somebody can help me. Thanks in advance.
This is an example of a view that paints the whole view pink and cuts a centered, circular hole making the parent visible:
public class FocusView extends View {
private Paint mCutPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Bitmap mBitmap;
private Canvas mInternalCanvas;
public FocusView(Context context) {
super(context);
init();
}
public FocusView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FocusView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mCutPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (mInternalCanvas != null) {
mInternalCanvas.setBitmap(null);
mInternalCanvas = null;
}
if (mBitmap != null) {
mBitmap.recycle();
mBitmap = null;
}
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mInternalCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
if (mInternalCanvas == null || mBitmap == null) {
return;
}
final int width = getWidth();
final int height = getHeight();
// make the radius as large as possible within the view bounds
final int radius = Math.min(width, height) / 2;
mInternalCanvas.drawColor(0xFFFF00FF);
mInternalCanvas.drawCircle(width / 2, height / 2, radius, mCutPaint);
canvas.drawBitmap(mBitmap, 0, 0, null);
}
}
The reason for drawing to an internal Bitmap first is that if you apply PorterDuff.Mode.CLEAR to the original Canvas it will cut away everything that's been previously drawn to the canvas, including the parent view.
There may be better solutions out there, but this one is simple enough to understand.
I am trying to clip paths in my imageview. But nothing is happening.
My ImageView
public static class CliptImageView extends ImageView {
Path path = new Path();
public CliptImageView(Context context) {
super(context);
}
public CliptImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CliptImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
path.reset();
float y = getMeasuredHeight() / 2.0f;
float x = getMeasuredWidth() / 2.0f;
path.addCircle(x,y, 20,Path.Direction.CW);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.clipPath(path, Region.Op.DIFFERENCE);
super.onDraw(canvas);
canvas.restore();
}
}
I add the imageview programatically to a linearLayout like this
private View getMiddleArea() {
CliptImageView imageView = new CliptImageView(getContext());
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(
0, ViewGroup.LayoutParams.MATCH_PARENT, 2);
imageView.setLayoutParams(params);
imageView.setBackgroundColor(ContextCompat.getColor(getContext(),R.color.white));
// imageView.setBackgroundResource(R.drawable.bottom_bar_semicircle);
// imageView.getBackground().setLevel(5000);
return imageView;
}
Nothing happens. The view is kept white. So i am obviously doing something wrong. But i have no idea what. I have had a lot of trial and error the latest 2 days. But nothing seems to work.
So any help that would get me in the right path is appreciated
Edit update
This is what i am trying to achieve. a transparent circle that clips the view and makes everything transparent
I have a very simple customized EditText like this:
public class MyEditText extends EditText {
private Paint mPaint;
public MyEditText(Context context) {
super(context);
init();
}
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setSingleLine();
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(6);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int y = canvas.getHeight() * 6 / 7;
canvas.drawLine(0, y, canvas.getWidth(), y, mPaint);
}
}
As I set single line mode on, when text is short everything is fine, it would look like this:
But once the text gets longer (more than width of the EditText), the red line is shifted to the left like this:
As you'll probably notice I used 0 and canvas.getWidth() to connect both sides of the view, but the line gets shifted, so doesn't it mean the whole canvas gets shifted as well?
If so it's such a strange behavior that I didn't expect from a View descendant. Can someone shed me some light on this strange behavior?
Thanks
Change your onDraw() method like below...
#Override
protected void onDraw(Canvas canvas) {
Rect r = new Rect();
int baseline = getLineBounds(0, r);
int y = canvas.getHeight() * 6 / 7;
canvas.drawLine(r.left, y, r.right, y, mPaint);
super.onDraw(canvas);
}
I want to rotate an ImageView toward specific pivot and with special degree. I searched in Google and found some solution about this, but I didn't find complete answer about this (like this answer).
I tried to use this code, but ImageView didn't rotate! Just the background of it rotates (without rotating view rectangle)
public class ImageViewCustom extends ImageView {
public Context M_context;
public ImageViewCustom(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.M_context = context;
}
public ImageViewCustom(Context context, AttributeSet attrs) {
super(context, attrs);
this.M_context = context;
}
public ImageViewCustom(Context context) {
super(context);
this.M_context = context;
}
public float xPivot;
public float yPivot;
public float degree;
public void draw(Canvas canvas) {
canvas.save();
canvas.rotate(degree, xPivot, yPivot);
super.draw(canvas);
canvas.restore();
}
}
So, how can I rotating ImageView without using Animation and just with overriding or adding rotate methods to ImageViewCustom ?
Thanks in advance :)
Bitmap bmp = arrow.copy(Bitmap.Config.ARGB_8888, true);
Matrix matrix = new Matrix();
matrix.postRotate(direction);
Bitmap bmpRotated = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(),bmp.getHeight(), matrix, true);
iv.setImageBitmap(bmpRotated);
iv being the imageview and direction the degrees in whicht the bitmap needs to be rotated.