I have a project in which I am trying to draw rectangles to fill the screen
MainActivity.java
public class MainActivity extends Activity {
private int vScreenHeight, vScreenWidth;
private int vLeftPos = 0;
private int vTopPos = 0;
private int vRightPos = 154;
private int vBottomPos = 154;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vGetScreenHeightAndWidth();
while(vTopPos < vScreenHeight) {
while(vLeftPos < vScreenWidth) {
RectView rectView = new RectView(getApplicationContext(), vLeftPos, vTopPos, vRightPos, vBottomPos);
vLeftPos += 154;
vRightPos += 154;
setContentView(rectView);
}
vLeftPos = 0;
vTopPos += 154;
vRightPos = 154;
vBottomPos += 154;
}
}
private void vGetScreenHeightAndWidth() {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size); // this will work only in API level 13 above.
vScreenWidth = size.x;
vScreenHeight = size.y;
}
}
RectView.java
public class RectView extends View implements OnClickListener
{
private int vLeftPos;
private int vTopPos;
private int vRightPos;
private int vBottomPos;
Rect r;
private Paint paint = new Paint();
private final String TAG = "Canvas Application";
public RectView(Context pAppContext, int pLeftPos, int pTopPos, int pRightPos, int pBottomPos)
{
super(pAppContext);
vLeftPos = pLeftPos;
vTopPos = pTopPos;
vRightPos = pRightPos;
vBottomPos = pBottomPos;
r = new Rect();
this.setOnClickListener(this);
}
public void onDraw(Canvas pCanvasObj)
{
r.set(vLeftPos, vTopPos, vRightPos, vBottomPos);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
pCanvasObj.drawRect(r, paint);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.BLACK);
pCanvasObj.drawRect(r, paint);
}
#Override
public void onClick(View v)
{
Toast.makeText(null, "tapped", Toast.LENGTH_SHORT).show();
}
}
In this Activity, I am calculating the positions of the rectangles and creating a RectView object to draw the rectangles.
I am not able to understand what am I doing wrong ?
The problem is in RectView. You can try this:
public class RectView extends View {
private RectF rect;
private Paint paint;
/**
* #param context
*/
public RectView(Context context) {
super(context);
paint=new Paint();
paint.setColor(Color.RED);
rect=new RectF();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
rect.set(0, 0, MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(rect, paint);
}
Related
I want to show a text in the circle as a curve, so I wrote this code:
public class CircularTextView extends View {
private String text = "";
private Path circle;
private Paint tPaint;
int xAxis = 0, yAxis = 0;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
private Path _arc;
private Paint _paintText;
public CircularTextView(Context context, int cx, int cy) {
super(context);
this.xAxis = cx;
this.yAxis = cy;
_arc = new Path();
RectF oval = new RectF(xAxis,yAxis,0,yAxis/2);
_arc.addArc(oval, 0, 180);
_paintText = new Paint(Paint.ANTI_ALIAS_FLAG);
_paintText.setStyle(Paint.Style.FILL_AND_STROKE);
_paintText.setColor(Color.WHITE);
_paintText.setTextSize(Functions.convertDpToPixel(16, context));
_paintText.setTypeface(ResourcesCompat.getFont(context, R.font.quick_regular));
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawTextOnPath(getText(), _arc, xAxis/2, yAxis, _paintText);
invalidate();
}
For using this custom class i have written this code.
frameLayout.post(new Runnable() {
#Override
public void run() {
int cx = frameLayout.getMeasuredWidth() / 2;
int cy = frameLayout.getMeasuredHeight() / 2;
CircularTextView circularTextView = new CircularTextView(FreddyChooseActivity.this, cx, cy);
circularTextView.setLayoutParams(layoutParams);
circularTextView.setText(choiceData.get(finalI).getChoiceName());
frameLayout.addView(circularTextView);
}
});
above code is not working and it shows straight text not curved.
I want like this.
Advanced help would be appreciated!
I try to create like this drawable
I wrote code and almost working correctly
public class GetsugaDrawable extends Drawable {
private final Context context;
private final float radiusScale = 1.2f;
private final float yOffset = 0.3f;
private final int colorLower = Color.RED;
private final int colorUpper = Color.BLACK;
private final Paint upperPaint = new Paint();
public GetsugaDrawable(Context c) {
context = c;
upperPaint.setColor(colorUpper);
upperPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
}
#Override
public void draw(#NonNull Canvas canvas) {
final Rect bounds = new Rect(getBounds());
canvas.drawColor(colorLower, PorterDuff.Mode.SRC);
final float radius = radiusScale * bounds.height();
final int x = bounds.centerX();
final float y = (bounds.centerY() - bounds.height() * yOffset) - radius;
canvas.drawCircle(x, y, radius, upperPaint);
}
#Override
public void setAlpha(int alpha) {
// ignored TODO impl.
}
#Override
public void setColorFilter(#Nullable ColorFilter colorFilter) {
// ignored TODO impl.
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
Here is my result
I tried to change
private final int colorUpper = Color.BLACK;
with
private final int colorUpper = Color.TRANSPARENT;
but when I run my app again with transparent color, the result is like this
What am i doing wrong ?
Thanks
Add upperPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
public class GetsugaDrawable extends Drawable {
private final Context context;
private final float radiusScale = 1.2f;
private final float yOffset = 0.3f;
private final int colorLower = Color.RED;
private final int colorUpper = Color.BLACK;
private final Paint upperPaint = new Paint();
public GetsugaDrawable(Context c) {
context = c;
upperPaint.setAntiAlias(true);
upperPaint.setColor(colorUpper);
upperPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
#Override
public void draw(#NonNull Canvas canvas) {
final Rect bounds = new Rect(getBounds());
canvas.drawColor(colorLower);
final float radius = radiusScale * bounds.height();
final int x = bounds.centerX();
final float y = (bounds.centerY() - bounds.height() * yOffset) - radius;
canvas.drawCircle(x, y, radius, upperPaint);
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(#Nullable ColorFilter colorFilter) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}}
And don't forget to view.setLayerType(View.LAYER_TYPE_HARDWARE, null); on target view
You can change draw function.
#Override
public void draw(#NonNull Canvas canvas) {
final Rect bounds = new Rect(getBounds());
final float radius = radiusScale * bounds.height();
final int x = bounds.centerX();
final float y = (bounds.centerY() - bounds.height() * yOffset) - radius;
Path path = new Path();
path.addCircle(x, y, radius, CW);
canvas.clipPath(path, Region.Op.DIFFERENCE);
canvas.drawColor(colorLower);
}
Try this.
I'm creating a custom view in which I have a rectangle RectF object that have a specific height. I would like to increase the bottom Y point coordinate to a specific value with a progressive animation.
I've tried the following. I've created a method setBatteryState() that is called on a onclicked method in the activity that holds the custom view:
public class BatteryView extends View {
public int mCanvasWidth;
public int mCanvasHeight;
public RectF mBatteryHead;
public RectF mBatteryBody;
public RectF mBatteryBodyVolume;
public Canvas mCanvas;
public BatteryView(Context context) {
super(context);
}
public BatteryView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void init()
{
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
this.mCanvas = canvas;
float batteryHeadDistanceFromLeft = mCanvasWidth / 3;
float batteryHeadWidth = mCanvasWidth / 3;
float batteryBodyDistanceFromTop = mCanvasHeight / 5;
float batteryHeadHeight = mCanvasHeight / 5;
mBatteryHead = new RectF(batteryHeadDistanceFromLeft,0,2*batteryHeadWidth,batteryHeadHeight+5);
Paint batteryHeadPaint = new Paint();
batteryHeadPaint.setColor(ContextCompat.getColor(getContext(), R.color.batifyColor));
canvas.drawRect(mBatteryHead,batteryHeadPaint);
mBatteryBody = new RectF(0,(int)batteryBodyDistanceFromTop,mCanvasWidth,mCanvasHeight);
Paint batteryBodyPaint = new Paint();
batteryBodyPaint.setStyle(Paint.Style.STROKE);
batteryBodyPaint.setColor(ContextCompat.getColor(getContext(), R.color.batifyColor));
batteryBodyPaint.setStrokeWidth(10);
canvas.drawRect(mBatteryBody,batteryBodyPaint);
mBatteryBodyVolume = new RectF(12,(int)batteryBodyDistanceFromTop + 10,mCanvasWidth-12,mCanvasHeight/2);
Paint volumeBodyPaint = new Paint();
volumeBodyPaint.setColor(ContextCompat.getColor(getContext(), R.color.batifyColor));
canvas.drawRect(mBatteryBodyVolume,volumeBodyPaint);
}
public void setStateOnBattery(){
ObjectAnimator animateBottom = ObjectAnimator.ofFloat(mBatteryBodyVolume, "bottom", mBatteryBodyVolume.bottom, mCanvasHeight);
animateBottom.setDuration(1000).start();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
mCanvasWidth = MeasureSpec.getSize(widthMeasureSpec);
mCanvasHeight = MeasureSpec.getSize(heightMeasureSpec);
}}
ObjectAnimator should translate the rect mBatteryBodyVolume to the size of the canvas but nothing change...
Any Idea ?
Thanks in advance !
Use an asynchronous task with 2 major functions, draw and update. Every time update is called, increase the height variable by a constant. Then, in draw, draw your rectangle with height as a param. If you need code, just ask. :D
UPDATE
Create a 'runner' async task:
public class Runner extends Thread {
public volatile boolean running = true;
private Environment env;
public Runner(Environment E) {
env = E;
}
#Override
public void run() {
long lastTime = System.currentTimeMillis();
while(running) {
long now = System.currentTimeMillis();
long elapsed = now - lastTime;
env.update(elapsed);
env.draw();
lastTime = now;
}
}
public void shutdown() {
running = false;
}
}
In Environment, Do the following:
public void draw() {
Canvas canvas = holder.lockCanvas();
if (canvas != null) {
canvas.drawRect(x-w, y-h, x+w, y+h, myPaint);
holder.unlockCanvasAndPost(canvas);
}
}
and the update method:
public void update(float elapsedTime) {
h+=myKonstant*elpasedTime;
}
Hope I Helped :D
I would like to know if there is any simple solution to creating an overlay where an element would get highlighted.
So the final result would look something like this:
I would like to avoid using ShowcaseViewLibrary from variety of reason (it doesn't have the look I need, it's no longer supported etc.).
I thought about using FrameLayout but I am not sure how to achieve the highlighted existing element. Also putting the arrows or bubbles to the elements so they connect precisely.
A quick and easy way would be to make a copy of the Activity you want to demonstrate with overlays added and just show that. It's what I do and it works fine.
/**
* Created by Nikola D. on 10/1/2015.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class ShowCaseLayout extends ScrimInsetsFrameLayout {
private static final long DEFAULT_DURATION = 1000;
private static final int DEFAULT_RADIUS = 100;
private Paint mEmptyPaint;
private AbstractQueue<Pair<String, View>> mTargetQueue;
private int mLastCenterX = 600;
private int mLastCenterY = 100;
private ValueAnimator.AnimatorUpdateListener mAnimatorListenerX = new ValueAnimator.AnimatorUpdateListener() {
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onAnimationUpdate(ValueAnimator animation) {
mLastCenterX = (int) animation.getAnimatedValue();
setWillNotDraw(false);
postInvalidate();
}
};
private ValueAnimator.AnimatorUpdateListener mAnimatorListenerY = new ValueAnimator.AnimatorUpdateListener() {
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onAnimationUpdate(ValueAnimator animation) {
mLastCenterY = (int) animation.getAnimatedValue();
setWillNotDraw(false);
postInvalidate();
}
};
private ValueAnimator mCenterAnimatorX;
private ValueAnimator mCenterAnimatorY;
private boolean canRender = false;
private OnAttachStateChangeListener mAttachListener = new OnAttachStateChangeListener() {
#Override
public void onViewAttachedToWindow(View v) {
canRender = true;
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
#Override
public void onViewDetachedFromWindow(View v) {
canRender = false;
removeOnAttachStateChangeListener(this);
}
};
private long mDuration = DEFAULT_DURATION;
private int mRadius = (int) DEFAULT_RADIUS;
private Interpolator mInterpolator = new LinearOutSlowInInterpolator();
private ValueAnimator mRadiusAnimator;
private ValueAnimator.AnimatorUpdateListener mRadiusAnimatorListener = new ValueAnimator.AnimatorUpdateListener() {
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onAnimationUpdate(ValueAnimator animation) {
mRadius = (int) animation.getAnimatedValue();
}
};
private TextView mDescriptionText;
private Button mGotItButton;
private OnClickListener mExternalGotItButtonlistener;
private OnClickListener mGotItButtonClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
setNextTarget();
if (mExternalGotItButtonlistener != null) {
mExternalGotItButtonlistener.onClick(v);
}
}
};
private Animator.AnimatorListener mAnimatorSetListener = new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
setNextTarget();
invalidate();
//mDescriptionText.layout(mTempRect.left, mTempRect.bottom + mTempRect.bottom, mDescriptionText. );
}
};
private Rect mTempRect;
private Paint mBackgroundPaint;
private Bitmap bitmap;
private Canvas temp;
private int mStatusBarHeight = 0;
public ShowCaseLayout(Context context) {
super(context);
setupLayout();
}
public ShowCaseLayout(Context context, AttributeSet attrs) {
super(context, attrs);
setupLayout();
}
public ShowCaseLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setupLayout();
}
public void setTarget(View target, String hint) {
mTargetQueue.add(new Pair<>(hint, target));
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void setupLayout() {
mTargetQueue = new LinkedBlockingQueue<>();
setWillNotDraw(false);
mBackgroundPaint = new Paint();
int c = Color.argb(127, Color.red(Color.RED), Color.blue(Color.RED), Color.green(Color.RED));
mBackgroundPaint.setColor(c);
mEmptyPaint = new Paint();
mEmptyPaint.setColor(Color.TRANSPARENT);
mEmptyPaint.setStyle(Paint.Style.FILL);
mEmptyPaint.setAntiAlias(true);
mEmptyPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
if (!ViewCompat.isLaidOut(this))
addOnAttachStateChangeListener(mAttachListener);
else canRender = true;
mDescriptionText = new TextView(getContext());
mGotItButton = new Button(getContext());
mGotItButton.setText("GOT IT");
mGotItButton.setOnClickListener(mGotItButtonClickListener);
addView(mGotItButton, generateDefaultLayoutParams());
//ViewCompat.setAlpha(this, 0.5f);
}
#Override
protected LayoutParams generateDefaultLayoutParams() {
return new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!canRender) return;
temp.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mBackgroundPaint);
temp.drawCircle(mLastCenterX, mLastCenterY, mRadius, mEmptyPaint);
canvas.drawBitmap(bitmap, 0, 0, null);
}
#TargetApi(Build.VERSION_CODES.M)
private void animateCenterToNextTarget(View target) {
int[] locations = new int[2];
target.getLocationInWindow(locations);
int x = locations[0];
int y = locations[1];
mTempRect = new Rect(x, y, x + target.getWidth(), y + target.getHeight());
int centerX = mTempRect.centerX();
int centerY = mTempRect.centerY();
int targetRadius = Math.abs(mTempRect.right - mTempRect.left) / 2;
targetRadius += targetRadius * 0.05;
mCenterAnimatorX = ValueAnimator.ofInt(mLastCenterX, centerX).setDuration(mDuration);
mCenterAnimatorX.addUpdateListener(mAnimatorListenerX);
mCenterAnimatorY = ValueAnimator.ofInt(mLastCenterY, centerY).setDuration(mDuration);
mCenterAnimatorY.addUpdateListener(mAnimatorListenerY);
mRadiusAnimator = ValueAnimator.ofInt(mRadius, targetRadius);
mRadiusAnimator.addUpdateListener(mRadiusAnimatorListener);
playTogether(mCenterAnimatorY, mCenterAnimatorX, mRadiusAnimator);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
bitmap.eraseColor(Color.TRANSPARENT);
temp = new Canvas(bitmap);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void playTogether(ValueAnimator... animators) {
AnimatorSet set = new AnimatorSet();
set.setInterpolator(mInterpolator);
set.setDuration(mDuration);
set.playTogether(animators);
set.addListener(mAnimatorSetListener);
set.start();
}
public void start(Activity activity) {
if (getParent() == null) {
attachLayoutToWindow(activity);
}
setNextTarget();
}
private void setNextTarget() {
Pair<String, View> pair = mTargetQueue.poll();
if (pair != null) {
if (pair.second != null)
animateCenterToNextTarget(pair.second);
mDescriptionText.setText(pair.first);
}
}
private void attachLayoutToWindow(Activity activity) {
FrameLayout rootLayout = (FrameLayout) activity.findViewById(android.R.id.content);
rootLayout.addView(this);
}
public void hideShowcaseLayout() {
}
public void setGotItButtonClickistener(OnClickListener mExternalGotItButtonlistener) {
this.mExternalGotItButtonlistener = mExternalGotItButtonlistener;
}
public TextView getDescriptionTextView() {
return mDescriptionText;
}
public void setDescriptionTextView(TextView textView) {
mDescriptionText = textView;
}
}
Please note that this code is incomplete and is under development, you should tweak it according your needs.
This layout will draw a circle around the View over its Rect.
Instead of drawing the circle you could drawRect to the Rect bounds of the target view or drawRoundRect if the View's Rect and background drawable Rect are complementary.
Drawing the line (drawLine()) should be from the target view:
startX = (rect.right - rect.left)/2;
startY = rect.bottom;
endX = startX;
endY = startY + arbitraryLineHeight;
if the endY is larger than the layout height you should be drawing it upwards rect.top - arbitraryLineHeight, otherwise you draw it as it is.
arbitraryLineHeight could be descriptionViewRect.top which makes it more dynamic, instead of using a constant value.
I have a drawable that draws a progress bar using onLevelChange and calls draw() to make a line at bottom on canvas. How can I animate this line draw?
public class BorderProgressDrawable extends Drawable {
private static final int MAX_LEVEL = 10000;
private int mLevel = 0;
private Paint mPaint;
public BorderProgressDrawable(Context context) {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(context.getResources().getColor(R.color.accent));
mPaint.setStrokeWidth((float) CommonMethods.dpToPx(context.getResources().getDisplayMetrics(), 4));
}
#Override
public void draw(final Canvas canvas) {
int width = canvas.getWidth();
int height = canvas.getHeight();
float visibleWidth = (((float) mLevel) / MAX_LEVEL) * width;
canvas.drawLine(0, height, visibleWidth, height, mPaint);
}
#Override
public void setAlpha(int i) {
mPaint.setAlpha(i);
}
#Override
public void setColorFilter(ColorFilter colorFilter) {
if (colorFilter != null) mPaint.setColorFilter(colorFilter);
}
#Override
public int getOpacity() {
return mPaint.getAlpha();
}
#Override
protected boolean onLevelChange(int level) {
mLevel = level;
return true;
}
}