I am having a line that I draw it using "canvas.drawLine(250, 400 , 250 , 200, p3 )" , I want to rotate it using the rotateAnimation , is there away to do it ?
when I try to put the drawLine(...) in a method it getting no compiled...
import android.widget.Toast;
class Circles<Graphics> extends View
{
public Circles(Context context)
{
super(context);
}
public void onDraw(final Canvas canvas)
{
super.onDraw(canvas);
//2 Circels
Paint p1 = new Paint();
p1.setColor(Color.BLUE);
p1.setStyle(Style.STROKE);
Paint p2 = new Paint();
p2.setColor(Color.RED);
p2.setStyle(Style.FILL);
canvas.drawCircle(250, 400, 250, p1);
canvas.drawCircle(250, 400, 20, p2);
// invalidate();
// Seconds
final Paint p3 = new Paint();
p3.setColor(Color.RED);
p3.setStyle(Style.FILL);
int b1 ;
Runnable seconds = new Runnable() {
public void run() {
try {
int seconds = 0;
RotateAnimation rotateAnimation = new RotateAnimation(
(seconds - 1) * 6, seconds * 6,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setInterpolator(new LinearInterpolator());
rotateAnimation.setDuration(1000);
rotateAnimation.setFillAfter(true);
// now rotate this canvas.drawLine(250, 400 , 250 , 200, p3 ) ;
} catch (Exception e) {
}
}
};
}
If you want to use animation for drawing circle line use my code.
There is an animation which only gives you interpolated time of rotate animation, so you can simply refresh the toAngleValue and refresh the drawing state for smoothy your line draw.
/**
* Created by GIGAMOLE on 17.06.2015.
*/
public class CustomView extends View {
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
startAnimation(new CustomAnimation(fromAngleValue, toAngleValue));
setWillNotDraw(false);
}
//Out values for angle circle
private float fromAngleValue = 0f;
private float toAngleValue = 360f;
private float currentAngleValue;
//Paint
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG) {
{
setDither(true);
setColor(Color.RED);
setStrokeWidth(5);
setStyle(Style.STROKE);
}
};
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//Always draw arc and invalidate it in animation
canvas.drawArc(
new RectF(
50,
50,
getWidth() - 50,
getHeight() - 50
),
fromAngleValue,
currentAngleValue,
false,
paint
);
}
private class CustomAnimation extends RotateAnimation {
public CustomAnimation(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomAnimation(float fromDegrees, float toDegrees) {
super(fromDegrees, toDegrees);
setDuration(3000);
setFillAfter(true);
}
public CustomAnimation(float fromDegrees, float toDegrees, float pivotX, float pivotY) {
super(fromDegrees, toDegrees, pivotX, pivotY);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
currentAngleValue = interpolatedTime * toAngleValue;
invalidate();
//Change current value relative to animation
}
}
}
Also you can use esiest method which only increment value with post invalidate, but there is no features like concret duration and any kind of intelpolators.
/**
* Created by GIGAMOLE on 17.06.2015.
*/
public class CustomView extends View {
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setWillNotDraw(false);
}
//Out values for angle circle
private float fromAngleValue = 0f;
private float toAngleValue = 360f;
private float currentAngleValue;
//Paint
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG) {
{
setDither(true);
setColor(Color.RED);
setStrokeWidth(5);
setStyle(Style.STROKE);
}
};
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//Always draw arc and invalidate it in animation
canvas.drawArc(
new RectF(
50,
50,
getWidth() - 50,
getHeight() - 50
),
fromAngleValue,
currentAngleValue,
false,
paint
);
if (currentAngleValue <= toAngleValue) {
currentAngleValue++;
postInvalidateDelayed(1);
}
}
}
Related
Is there a way that can I make the cap/dot rounded, like in the attached picture?
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<stroke
android:width="2dp"
android:color="#color/grey"
android:dashWidth="3dp"
android:dashGap="3dp" />
</shape>
NOTE
Guys, I know how to make a dotted line, I'm asking how to make a "rounded" dashes.!! look at this picture from Adobe XD to know what I mean..!
You can achieve a goal using a custom view and drawing on canvas. Please, try this and adjust sizes/styling for your needs:
public class RoundedDashView extends View {
public enum Orientation {
VERTICAL,
HORIZONTAL
}
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Path path = new Path();
private Orientation orientation = Orientation.HORIZONTAL;
public RoundedDashView(Context context) {
super(context);
init();
}
public RoundedDashView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundedDashView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public RoundedDashView(Context context, #Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(10);
paint.setColor(Color.GRAY);
paint.setPathEffect(new DashPathEffect(new float[]{20, 25}, 20));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path.reset();
if (orientation == Orientation.VERTICAL) {
path.moveTo(getWidth() / 2, 0);
path.quadTo(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight());
} else {
path.moveTo(0, getHeight() / 2);
path.quadTo(getWidth() / 2, getHeight() / 2, getWidth(), getHeight() / 2);
}
canvas.drawPath(path, paint);
}
public void setOrientation(Orientation orientation) {
this.orientation = orientation;
invalidate();
}
}
I used the answer above and modified it to make it configurable in the xml. Copy the java class:
public class RoundedDashView extends View {
private static final int HORIZONTAL = 0;
private static final int VERTICAL = 1;
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Path path = new Path();
private float gap = 6f;
private float width = 8f;
private int orientation = HORIZONTAL;
private int color = getResources().getColor(R.color.dot_inactive);
public RoundedDashView(Context context) {
super(context);
init();
}
public RoundedDashView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundedDashView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundedDashView, defStyleAttr, R.style.RoundedDasViewDefault);
orientation = a.getInt(R.styleable.RoundedDashView_orientation, VERTICAL);
color = a.getColor(R.styleable.RoundedDashView_dividerDashColor, color);
gap = a.getFloat(R.styleable.RoundedDashView_dividerDashGap, gap);
width = a.getFloat(R.styleable.RoundedDashView_dividerDashWidth, width);
init();
a.recycle();
}
public void init() {
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(gap);
paint.setColor(color);
paint.setPathEffect(new DashPathEffect(new float[]{gap, width}, gap));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path.reset();
applyOrientation();
canvas.drawPath(path, paint);
}
public void setOrientation(int orientation) {
this.orientation = orientation;
applyOrientation();
invalidate();
}
public void applyOrientation() {
if (orientation == VERTICAL) {
path.moveTo((float) getWidth() / 2, 0);
path.quadTo((float) getWidth() / 2, (float) getHeight() / 2, (float) getWidth() / 2, getHeight());
} else if (orientation == HORIZONTAL) {
path.moveTo(0, (float) getHeight() / 2);
path.quadTo((float) getWidth() / 2, (float) getHeight() / 2, getWidth(), (float) getHeight() / 2);
}
}
public void setColor(int color) {
this.color = color;
paint.setColor(color);
invalidate();
}
public int getColor() {
return color;
}
}
Create an attr file in the /res directory and add this
<declare-styleable name="RoundedDashView">
<attr name="dividerDashGap" format="float" />
<attr name="dividerDashWidth" format="float" />
<attr name="dividerDashColor" format="reference|color" />
<attr name="orientation" format="enum">
<enum name="vertical" value="1" />
<enum name="horizontal" value="0" />
</attr>
</declare-styleable>
Add a style to the styles file
<style name="RoundedDasViewDefault">
<item name="dividerDashGap">6</item>
<item name="dividerDashWidth">8</item>
<item name="dividerDashColor">#color/dot_inactive</item>
<item name="orientation">horizontal</item>
</style>
Set attributes in XML
<com.neon.robinfood.utils.RoundedDashView
android:layout_width="6dp"
android:layout_marginStart="8dp"
android:layout_height="#dimen/dimen_36dp"
app:dividerDashGap="6"
app:dividerDashWidth="8"
app:dividerDashColor="#color/red"
app:orientation="vertical"/>
I have a custom Imageview class like below. I have a field called timeInterval which I pass it in constructor, but in onDraw it's value is 0. What is the proper way to pass this? also I don't know if I can pass it dynamically as attribute.
public class ProgressBarView extends AppCompatImageView {
private final Handler mHandler = new Handler();
private int mTimeInterval;
private int mColor;
private int[] mLocations = new int[2];
public ProgressBarView(Context context, int timeInterval) {
super(context);
mTimeInterval = timeInterval;
init(null);
}
public ProgressBarView(Context context, AttributeSet attrst) {
super(context, attrst);
init(attrst);
}
public ProgressBarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
private void init(AttributeSet attrs) {
if (attrs == null) {
return;
}
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ProgressBarView);
mColor = typedArray.getColor(R.styleable.ProgressBarView_overlay_color, Color.BLACK);
}
public void updatePainting() {
mHandler.postDelayed(this::invalidate, mTimeInterval / 360);
}
#Override
public void onDraw(final Canvas canvas) {
if (mTimeInterval == 0) {
return;
}
Calendar now = Calendar.getInstance();
int seconds = now.get(Calendar.SECOND);
int mStartAngel = (int) (((float) (seconds % (mTimeInterval / 1000))
/ (mTimeInterval / 1000)) * 360);
final Paint paint = new Paint(Paint.DITHER_FLAG);
paint.setColor(mColor);
paint.setStyle(Paint.Style.FILL);
paint.setAlpha(-50);
getLocationOnScreen(mLocations);
int radius = getWidth() / 2;
float centreX = this.getX() + radius;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc(centreX - radius, centreX - radius, centreX + radius, centreX + radius, 0, mStartAngel, true, paint);
} else {
final RectF oval = new RectF();
oval.set(centreX - radius, centreX - radius, centreX + radius, centreX + radius);
canvas.drawArc(oval, 0, mStartAngel, true, paint);
}
updatePainting();
}
}
I instantiate it like this:
mProgressBarView = new ProgressBarView(getContext(), timeInterval);
You forgot about "this"
public ProgressBarView(Context context, int timeInterval) {
super(context);
this.mTimeInterval = timeInterval;
init(null);
}
I have a method to Cropped image to circle and work fine but need scale type to center crop or center in image but dont work if I define in XML file.
In xml value= SCALE TYPE= CENTER_CROP OR SCALE_TYPE CENTER
This is my class button:
public class CircleImage extends ImageView {
public CircleImage(Context context) {
super(context);
}
public CircleImage(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleImage(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
if (getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap b = ((BitmapDrawable) drawable).getBitmap();
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
int w = getWidth(), h = getHeight();
Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
canvas.drawBitmap(roundBitmap, 0, 0, null);
}
public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
Bitmap sbmp;
if (bmp.getWidth() != radius || bmp.getHeight() != radius) {
float smallest = Math.min(bmp.getWidth(), bmp.getHeight());
float factor = smallest / radius;
sbmp = Bitmap.createScaledBitmap(bmp, (int)(bmp.getWidth() / factor), (int)(bmp.getHeight() / factor), false);
} else {
sbmp = bmp;
}
Bitmap output = Bitmap.createBitmap(radius, radius,
Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xffa19774;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, radius, radius);
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawCircle(radius / 2 + 0.7f,
radius / 2 + 0.7f, radius / 2 + 0.1f, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(sbmp, rect, rect, paint);
return output;
}
}
Pass a complete and fixed class for circle image and center scale type
public class CircleImage extends ImageView {
public CircleImage(Context context) {
super(context);
}
public CircleImage(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleImage(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
if (getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap b = ((BitmapDrawable) drawable).getBitmap();
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
int w = getWidth(), h = getHeight();
Bitmap bm_scale_center_crop;
if (bitmap.getWidth() >= bitmap.getHeight()){
bm_scale_center_crop = Bitmap.createBitmap(
bitmap,
bitmap.getWidth()/2 - bitmap.getHeight()/2,
0,
bitmap.getHeight(),
bitmap.getHeight()
);
}else{
bm_scale_center_crop = Bitmap.createBitmap(
bitmap,
0,
bitmap.getHeight()/2 - bitmap.getWidth()/2,
bitmap.getWidth(),
bitmap.getWidth()
);
}
Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
canvas.drawBitmap(roundBitmap, 0, 0, null);
}
I'm trying to get the text view '2' (in black) to appear in the centre of my view but for some reason it won't appear. Does anyone know what's wrong here and how this error can be fixed? Is there way of showing it and changing the colour of it programmatically rather than using XML?
XML
<com.apptacularapps.car.RectangleTextView
android:layout_width="120dp"
android:layout_height="40dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="2"
android:gravity="center"
android:background="#808080"/>
Java
public class RectangleTextView extends View {
Paint paint;
private TextPaint mTextPaint;
public RectangleTextView(Context context) {
super(context);
init();
}
public RectangleTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RectangleTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paint = new Paint();
paint.setColor(Color.RED);
paint.setStrokeWidth(1); // convert to dp?
paint.setStyle(Paint.Style.STROKE); // delete line for filled rect
mTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setColor(Color.BLACK);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText("2", 0, 0, paint);
paint.setTextSize(20);
int w = canvas.getWidth();
int h = canvas.getHeight();
int rectWidth = w/5;
int space = w/15;
int topRectHeight = getPaddingTop();
int bottomRectHeight = getPaddingBottom();
for (int i = 0; i < 4; i++) {
int left = i * (rectWidth + space);
int right = left + rectWidth;
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, paint);
Rect rect2 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, paint);
}
}
}
You do not have a paint object that defines how your text will be drawn and neither have you called canvas.drawText() in your onDraw() method. Do it this way:
private TextPaint mTextPaint;
private void init() {
mTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
// You can tweak the appearance of the textpaint here
mTextPaint.setTextAlign(Align.CENTER);
mTextPaint.setColor(color);
}
#Override
public void onDraw() {
super.onDraw()
// You can tweak the positioning of the text here
canvas.drawText("2", 25, 25, mTextPaint);
}
I need to denote progress by the border of view.
E.g. Initially view will not have any border at all, when 50% progress is reached, only 50% of view will get border.Find the attached image.
I did lot of googling but no luck.The view I used is textview.
Edited
The following code, cuts the edges of bitmap.
What I've done in this code is -
1. Bg is set to Black Hexagon
2. And I've taken hollow green bordered hexagon & revealing this hollow hexagon, so that it will look like border is getting accumulated.
public class MyView extends View {
private Bitmap mBitmap;
private Paint mPaint;
private RectF mOval;
private float mAngle = 135;
private Paint mTextPaint;
private Bitmap bgBitmap;
public MyView(Context context) {
super(context);
doInit();
}
/**
* #param context
* #param attrs
* #param defStyleAttr
*/
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
doInit();
}
/**
* #param context
* #param attrs
*/
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
doInit();
}
private void doInit() {
// use your bitmap insted of R.drawable.ic_launcher
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.hexagon_border);
bgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.view_message_small_hexagon);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mOval = new RectF();
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setTextSize(48);
mTextPaint.setTextAlign(Align.CENTER);
mTextPaint.setColor(0xffffaa00);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Matrix m = new Matrix();
RectF src = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
RectF dst = new RectF(0, 0, w, h);
m.setRectToRect(src, dst, ScaleToFit.CENTER);
Shader shader = new BitmapShader(mBitmap, TileMode.CLAMP, TileMode.CLAMP);
shader.setLocalMatrix(m);
mPaint.setShader(shader);
m.mapRect(mOval, src);
}
#Override
protected void onDraw(Canvas canvas) {
//canvas.drawColor(0xff0000aa);
Matrix matrix = new Matrix();
canvas.drawBitmap(bgBitmap, matrix, null);
canvas.drawArc(mOval, -90, mAngle, true, mPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float w2 = getWidth() / 2f;
float h2 = getHeight() / 2f;
mAngle = (float) Math.toDegrees(Math.atan2(event.getY() - h2, event.getX() - w2));
mAngle += 90 + 360;
mAngle %= 360;
invalidate();
return true;
}
}
try this SO answer:
public class MyView extends View {
private Bitmap mBitmap;
private Paint mPaint;
private RectF mOval;
private float mAngle = 135;
private Paint mTextPaint;
public MyView(Context context) {
super(context);
// use your bitmap insted of R.drawable.ic_launcher
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mOval = new RectF();
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setTextSize(48);
mTextPaint.setTextAlign(Align.CENTER);
mTextPaint.setColor(0xffffaa00);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Matrix m = new Matrix();
RectF src = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
RectF dst = new RectF(0, 0, w, h);
m.setRectToRect(src, dst, ScaleToFit.CENTER);
Shader shader = new BitmapShader(mBitmap, TileMode.CLAMP, TileMode.CLAMP);
shader.setLocalMatrix(m);
mPaint.setShader(shader);
m.mapRect(mOval, src);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xff0000aa);
canvas.drawArc(mOval, -90, mAngle, true, mPaint);
canvas.drawText("click me", getWidth() / 2, getHeight() / 2, mTextPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float w2 = getWidth() / 2f;
float h2 = getHeight() / 2f;
mAngle = (float) Math.toDegrees(Math.atan2(event.getY() - h2, event.getX() - w2));
mAngle += 90 + 360;
mAngle %= 360;
invalidate();
return true;
}
}
Getting a good circular progress spinner is difficult in itself. The ProgressWheel is a good custom View that does this. You should be able to modify the ProgressWheel's onDraw() class to do something very similar to what you want.