I am fairly new to Java and android studio. I would like to animate my bar which I created with random value. I have created customView with android studio and drawn a canvas rectangle. Next step is feed some random values and animate the bar. I acheived this feat with (Math.random) in JavaScript.
public class CustomView extends View {
private Rect rect;
private Paint paint;
int radius;
public CustomView(Context context){
super(context);
init(null);
}
public CustomView(Context context, AttributeSet attrs){
super(context, attrs);
init(attrs);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr){
super(context, attrs, defStyleAttr);
init(attrs);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes){
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs);
}
private void init(#Nullable AttributeSet set){
rect = new Rect();
// the flag is more pixelated
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
postInvalidate();
}
//drawing a canvas
#Override
protected void onDraw(Canvas canvas){
int viewWidth = getWidth();
int viewHeight = getHeight();
int leftTopX = viewWidth - 750;
int leftTopY = viewHeight - 750;
int rightBotX = viewWidth + 150;
int rightBotY = viewHeight + 150;
paint.setColor(Color.MAGENTA);
canvas.drawRect(leftTopX,leftTopY, rightBotX,rightBotY,paint);
paint.setColor(Color.GREEN);
}
}
This is what I have achieved so far by now.But how can I animate bar with Java ?
Try this -
I used it with seekbar. You can use it for your view. As per your case. You should Progressbar or Seekbar.
seekbar = ((CustomSeekbar) findViewById(R.id.customSeekBar));
seekbar.setMax(2600);
final ObjectAnimator animation = ObjectAnimator.ofInt(seekbar, "progress", 0, 800;
animation.setDuration(1500);
animation.setInterpolator(new DecelerateInterpolator());
animation.start();
seekbar.clearAnimation();
Here 0 is the starting value and 800 is the max value. Please change is as per your requirement.
Related
I created a class that extends LinearLayout to draw a border-radius and added the setRadius() function
public class RadiusLinearLayout extends LinearLayout {
private float CORNER_RADIUS;
private Bitmap maskBitmap;
private Paint paint, maskPaint;
private float cornerRadius;
public void setRadius(float cornerRadius) {
CORNER_RADIUS = cornerRadius;
}
public RadiusLinearLayout(Context context) {
super(context);
init(context, null, 0);
}
public RadiusLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public RadiusLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
setWillNotDraw(false);
}
#Override
public void draw(Canvas canvas) {
Bitmap offscreenBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas offscreenCanvas = new Canvas(offscreenBitmap);
super.draw(offscreenCanvas);
if (maskBitmap == null) {
maskBitmap = createMask(getWidth(), getHeight());
}
offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, maskPaint);
canvas.drawBitmap(offscreenBitmap, 0f, 0f, paint);
}
private Bitmap createMask(int width, int height) {
Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
Canvas canvas = new Canvas(mask);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
canvas.drawRect(0, 0, width, height, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, paint);
return mask;
}
}
On the fragment that corresponds to this class, OnCreateView I refence the Layout and set the radius value but it doesn't apply the value I send to the layout
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.calculator_fragment, container, false)
val test = view.findViewById(R.id.testCF) as RadiusLinearLayout
test.setRadius(2f)
return view
}
Is it possible to pass a value to the Layout before the fragment gets inflated?
Is it possible to pass a value to the Layout before the fragment gets inflated?
Basically yes (*), but I'd like to show how to change the radius of your custom View more flexibly:
There are certain changes to a View which make it necessary to update the UI, for example if you call View.setBackground().
In such cases, the View calls invalidate() to let the runtime know that it needs to be redrawn.
Your custom View can do so each time the radius is set:
public void setRadius(float cornerRadius) {
CORNER_RADIUS = cornerRadius;
// Now you need to calculate the field *cornerRadius* once more
//
DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics);
invalidate();
}
By the way, setting the corner radius to 2f does not cause that much of a change - I tried with 24f, and it worked fine.
(*) If you absolutely need to change the radius before the custom View is inflated, you can either create it programmatically and call setRadius() before adding it to a ViewGroup.
Or you define a custom attribute to configure the View via the layout file.
Solution 1: It seems you have declared same name of a variable cornerRadius which is declared globally and parameter of setradius method. It created ambiguity. Change the parameter name and do a try.
Something like this
private float cornerRadius;
public void setRadius(float radius) {
CORNER_RADIUS = radius;
}
Solution 2: Pass corner radius value by its constructor
Example:
public RadiusLinearLayout(Context context,float radius) {
super(context);
CORNER_RADIUS = radius;
init(context, null, 0);
}
I already know how to use a custom component in a xml. Now, I'm trying to call one programmatically. I haven't found any tutorial about this so I tried to do it like how we declare a view programmatically. One problem I stumbled upon is that how do I get an AttributeSet that I pass on my constructor? I don't know how I get or create that to pass it for my custom component.
This is my custom component class.
public class CheckOutItem extends ConstraintLayout {
public Context ctx;
public Paint mPaint;
public Rect mRect;
int mSquareColor;
public ImageView imgThumbnail;
public TextView lblAbbrev, lblFullName;
public ConstraintLayout lytMain;
String TAG = "sharePOS";
public CheckOutItem(Context context) {
super(context);
ctx = context;
init(null);
}
public CheckOutItem(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.checkout_item, this);
ctx = context;
init(attrs);
}
public CheckOutItem(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
ctx = context;
init(attrs);
}
private void init(#Nullable AttributeSet set){
//inflate(ctx, R.layout.checkout_item, this);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mRect = new Rect();
if(set == null){
return;
}
TypedArray ta = getContext().obtainStyledAttributes(set, R.styleable.CheckOutItem);
this.imgThumbnail = findViewById(R.id.imgItemThumbnail);
this.lblAbbrev = findViewById(R.id.lblItemAbbrevName);
this.lblFullName = findViewById(R.id.lblItemFullName);
this.lytMain = findViewById(R.id.lytMain);
this.lblAbbrev.setText(ta.getText(R.styleable.CheckOutItem_abbrevText));
this.lblAbbrev.setTextSize(ta.getDimension(R.styleable.CheckOutItem_abbrevTextSize, 1f));
this.lblAbbrev.setTextColor(ta.getColor(R.styleable.CheckOutItem_abbrevTextColor, Color.BLACK));
this.lblFullName.setText(ta.getText(R.styleable.CheckOutItem_fullNameText));
this.lblFullName.setTextSize(ta.getDimension(R.styleable.CheckOutItem_fullNameTextSize, 1f));
this.lblFullName.setTextColor(ta.getColor(R.styleable.CheckOutItem_fullNameTextColor, Color.BLACK));
this.lblFullName.setBackgroundColor(ta.getColor(R.styleable.CheckOutItem_fullNameBackgroundColor, Color.WHITE));
this.lytMain.setBackgroundColor(ta.getColor(R.styleable.CheckOutItem_mainBackgroundColor, Color.LTGRAY));
this.lytMain.setBackground(ta.getDrawable(R.styleable.CheckOutItem_mainBackgroundDrawable));
ta.recycle();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mRect.left = 0;
mRect.right = getWidth();
mRect.top = 0;
mRect.bottom = getHeight();
Log.d(TAG, "rect: " + mRect);
canvas.drawRect(mRect, mPaint);
}
}
UPDATE:
How do I set a margin in the custom component? Regular LayoutParams with setMargins() doesn't seem to work.
I've implemented a View with a Text.Layout and I'm drawing it but I'm getting nothing. Here is my code
public class MyEfficientTextView extends View {
Layout textLayout;
SpannableStringBuilder spannableStringBuilder;
int width = 0, height = 0;
TextPaint textPaint;
CharSequence text;
public MyEfficientTextView(Context context) {
this(context, null, 0);
}
public MyEfficientTextView(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyEfficientTextView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
spannableStringBuilder = new SpannableStringBuilder();
}
public void setText(CharSequence charSequence) {
text = charSequence;
spannableStringBuilder.clear();
spannableStringBuilder.append(text);
textPaint = new TextPaint();
textPaint.setAntiAlias(true);
textPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
textPaint.setColor(getResources().getColor(R.color.textColor));
textLayout = new StaticLayout(spannableStringBuilder, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
invalidate();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w != width) {
width = w;
setText(text);
}
height = h;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
if (textLayout != null) {
canvas.translate(getPaddingLeft(), getPaddingTop());
textLayout.draw(canvas);
}
canvas.restore();
}
}
this code is just for testing if it's working or not and it's not efficient. Which part is wrong and causing it to not render text?
you should override onMeasure and set the view width/height. your example code will result in default width/height (probably 0).
Parent layout has a specified width value (50dp), and height set to MATCH_PARENT. In that layout I am adding a few ImageView widgets using Java, and because parent layout has specified width, I can set width and height of each ImageView to MATCH_PARENT and using Java I can make that ImageView square by setting its height as width.
This is my code:
public class Icon extends ImageView {
public AppIcon(final Context context)
{
super(context);
}
public AppIcon(final Context context, final AttributeSet attrs)
{
super(context, attrs);
}
public AppIcon(final Context context, final AttributeSet attrs, final int defStyle)
{
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(final int width, final int height)
{
setMeasuredDimension(width, width);
}
}
Is this a good method to make each ImageView square? I think it's too simple, like something is missing.
P.S.: My method works, but I need to be sure, that everything is fine.
Your code is working one but it can be enhanced. See my code:
Updated my code.
The image will be scaled based on the measured width and height and whichever is smaller.
public class Icon extends ImageView {
public Icon(final Context context) {
super(context);
}
public Icon(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public Icon(final Context context, final AttributeSet attrs,
final int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int width, int height) {
super.onMeasure(width, height);
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
if (measuredWidth > measuredHeight) {
setMeasuredDimension(measuredHeight, measuredHeight);
} else {
setMeasuredDimension(measuredWidth, measuredWidth);
}
}
}
In my application i can scaling an ImageView using this class
`public class resizeAvatar extends View {
private final Drawable sfondoAvatar;
public resizeAvatar(Context context) {
super(context);
sfondoAvatar = context.getResources().getDrawable(R.drawable.main_voice);
setBackgroundDrawable(sfondoAvatar);
}
public resizeAvatar(Context context, AttributeSet attrs) {
super(context, attrs);
sfondoAvatar = context.getResources().getDrawable(R.drawable.main_voice);
setBackgroundDrawable(sfondoAvatar);
}
public resizeAvatar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
sfondoAvatar = context.getResources().getDrawable(R.drawable.main_voice);
setBackgroundDrawable(sfondoAvatar);
}
#Override
protected void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = width * sfondoAvatar.getIntrinsicHeight() / sfondoAvatar.getIntrinsicWidth();
setMeasuredDimension(width, height);
}
}
`
And writing in the layout:
<com.myapp.app.resizeAvatar
android:id="#+id/mainvoice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_centerVertical="true"/>
But in this way i can't have the onClick event.. i need do the same but using an ImageButton.. Is there a way?
In the activity where you include this view and in the onCreate method do the following:
resizeAvatar myMainvoice = (resizeAvatar) v.findViewById(R.id.mainvoice);
myMainVoice.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
//place your on click logic here
}
});