Android Background image is deformed in repeat - android

I use android:tileMode="repeat" for my textview backgrnound. It is about 1px height image,but in repeat is deformed on left,right side..
thanks for help!
screen: http://i.stack.imgur.com/yCXSQ.png
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/chat_rep"
android:dither="true"
android:tileMode="repeat" />

Call this function with each view that has the background:
public static void fixBackgroundRepeat(View view) {
Drawable bg = view.getBackground();
if (bg != null) {
if (bg instanceof BitmapDrawable) {
BitmapDrawable bmp = (BitmapDrawable) bg;
bmp.mutate(); // make sure that we aren't sharing state anymore
bmp.setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
}
}
}
This was an answer posted on this question:
"Tiled drawable sometimes stretches"

Related

Android change drawable solid color programmatically

I have a drawable that is an oval shape with a with check mark inside.
Is it possible to change the oval color programmatically without changing the check mark color ?
Here's my drawable:
<item>
<shape
android:shape="oval">
<solid android:color="#color/black" />
</shape>
</item>
<item>
<bitmap
android:src="#drawable/check_mark"/>
</item>
What I would like to do is only change the solid black color to something else programmatically
It would be easier to just add a second drawables with other "oval"-color and then replace the drawable programmatically.
You can grammatically create a shape using below reference code.
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius(24);
shape.setShape(GradientDrawable.OVAL);
shape.setColor(R.color.red);
imageView.setBackground(shape);
The drawable is an oval and is the background of an ImageView
Get the Drawable from imageView using getBackground():
Drawable background = imageView.getBackground();
Check against usual suspects:
if (background instanceof ShapeDrawable) {
// cast to 'ShapeDrawable'
ShapeDrawable shapeDrawable = (ShapeDrawable) background;
shapeDrawable.getPaint().setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof GradientDrawable) {
// cast to 'GradientDrawable'
GradientDrawable gradientDrawable = (GradientDrawable) background;
gradientDrawable.setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof ColorDrawable) {
// alpha value may need to be set again after this call
ColorDrawable colorDrawable = (ColorDrawable) background;
colorDrawable.setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
}
Compact version:
Drawable background = imageView.getBackground();
if (background instanceof ShapeDrawable) {
((ShapeDrawable)background).getPaint().setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof GradientDrawable) {
((GradientDrawable)background).setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof ColorDrawable) {
((ColorDrawable)background).setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
}

How to change Shape solid color programmatically? [duplicate]

This question already has answers here:
Set android shape color programmatically
(18 answers)
Closed 3 years ago.
How can I change the <solid android:color= /> programmatically?
I defined a custom shape element:
my_item.xml:
<shape android:shape="oval">
<solid android:color="#FFFF0000"/>
</shape>
And reuse it in another layout:
grid_view.xml:
<LinearLayout>
<ImageView ... android:src="#drawable/my_item"
android:id="#+id/myitemid" />
</LinearLayout>
The following does not work:
public class ShapeItemAdapter extends BaseAdapter {
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
view = inflter.inflate(R.layout.grid_view, null);
ImageView shape = (ImageView) view.findViewById(R.id.myitemid);
shape.setBackgroundColor(0xBCCACA); //does not work
}
}
I turned out none of the answers provided here have been correct. Important is: use getDrawable() on the shape, not getBackground().
GradientDrawable shape = (GradientDrawable) icon.getDrawable();
shape.setColor(Color.BLACK);
Try This:-
Get your drawable from resources and change shape color.Then you can set as a background of image view.
GradientDrawable drawable = (GradientDrawable) mContext.getResources()
.getDrawable(R.drawable.todo_list_circle);
drawable.mutate();
drawable.setColor(mColor);
try this
ImageView shape = (ImageView) view.findViewById(R.id.myitemid);
GradientDrawable bgShape = (GradientDrawable)shape.getBackground();
bgShape.setColor(Color.BLACK);
Get ShapeDrawable and set color:
ImageView shape = (ImageView) view.findViewById(R.id.myitemid);
ShapeDrawable shapeDrawable = (ShapeDrawable) shape.getBackground();
shapeDrawable.getPaint().setColor(ContextCompat.getColor(context,R.color.my_color));
You may wait until layout has been drawn:
ViewTreeObserver to = shape.getViewTreeObserver();
to.addOnGlobalLayoutListener (new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
ImageView shape = (ImageView) view.findViewById(R.id.myitemid);
ShapeDrawable shapeDrawable = (ShapeDrawable) shape.getBackground();
shapeDrawable.getPaint().setColor(ContextCompat.getColor(context,R.color.my_color));
}
});

Set android shape color programmatically

I am editing to make the question simpler, hoping that helps towards an accurate answer.
Say I have the following oval shape:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:angle="270"
android:color="#FFFF0000"/>
<stroke android:width="3dp"
android:color="#FFAA0055"/>
</shape>
How do I set the color programmatically, from within an activity class?
Note: Answer has been updated to cover the scenario where background is an instance of ColorDrawable. Thanks Tyler Pfaff, for pointing this out.
The drawable is an oval and is the background of an ImageView
Get the Drawable from imageView using getBackground():
Drawable background = imageView.getBackground();
Check against usual suspects:
if (background instanceof ShapeDrawable) {
// cast to 'ShapeDrawable'
ShapeDrawable shapeDrawable = (ShapeDrawable) background;
shapeDrawable.getPaint().setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof GradientDrawable) {
// cast to 'GradientDrawable'
GradientDrawable gradientDrawable = (GradientDrawable) background;
gradientDrawable.setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof ColorDrawable) {
// alpha value may need to be set again after this call
ColorDrawable colorDrawable = (ColorDrawable) background;
colorDrawable.setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
}
Compact version:
Drawable background = imageView.getBackground();
if (background instanceof ShapeDrawable) {
((ShapeDrawable)background).getPaint().setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof GradientDrawable) {
((GradientDrawable)background).setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof ColorDrawable) {
((ColorDrawable)background).setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
}
Note that null-checking is not required.
However, you should use mutate() on the drawables before modifying them if they are used elsewhere. (By default, drawables loaded from XML share the same state.)
A simpler solution nowadays would be to use your shape as a background and then programmatically change its color via:
view.background.setColorFilter(Color.parseColor("#343434"), PorterDuff.Mode.SRC_ATOP)
See PorterDuff.Mode for the available options.
UPDATE (API 29):
The above method is deprecated since API 29 and replaced by the following:
view.background.colorFilter = BlendModeColorFilter(Color.parseColor("#343434"), BlendMode.SRC_ATOP)
See BlendMode for the available options.
Do like this:
ImageView imgIcon = findViewById(R.id.imgIcon);
GradientDrawable backgroundGradient = (GradientDrawable)imgIcon.getBackground();
backgroundGradient.setColor(getResources().getColor(R.color.yellow));
This question was answered a while back, but it can modernized by rewriting as a kotlin extension function.
fun Drawable.overrideColor(#ColorInt colorInt: Int) {
when (this) {
is GradientDrawable -> setColor(colorInt)
is ShapeDrawable -> paint.color = colorInt
is ColorDrawable -> color = colorInt
}
}
Try this:
public void setGradientColors(int bottomColor, int topColor) {
GradientDrawable gradient = new GradientDrawable(Orientation.BOTTOM_TOP, new int[]
{bottomColor, topColor});
gradient.setShape(GradientDrawable.RECTANGLE);
gradient.setCornerRadius(10.f);
this.setBackgroundDrawable(gradient);
}
for more detail check this link this
hope help.
hope this will help someone with the same issue
GradientDrawable gd = (GradientDrawable) YourImageView.getBackground();
//To shange the solid color
gd.setColor(yourColor)
//To change the stroke color
int width_px = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, youStrokeWidth, getResources().getDisplayMetrics());
gd.setStroke(width_px, yourColor);
Expanding on Vikram's answer, if you are coloring dynamic views, like recycler view items, etc.... Then you probably want to call mutate() before you set the color. If you don't do this, any views that have a common drawable (i.e a background) will also have their drawable changed/colored.
public static void setBackgroundColorAndRetainShape(final int color, final Drawable background) {
if (background instanceof ShapeDrawable) {
((ShapeDrawable) background.mutate()).getPaint().setColor(color);
} else if (background instanceof GradientDrawable) {
((GradientDrawable) background.mutate()).setColor(color);
} else if (background instanceof ColorDrawable) {
((ColorDrawable) background.mutate()).setColor(color);
}else{
Log.w(TAG,"Not a valid background type");
}
}
this is the solution that works for me...wrote it in another question as well:
How to change shape color dynamically?
//get the image button by id
ImageButton myImg = (ImageButton) findViewById(R.id.some_id);
//get drawable from image button
GradientDrawable drawable = (GradientDrawable) myImg.getDrawable();
//set color as integer
//can use Color.parseColor(color) if color is a string
drawable.setColor(color)
Nothing work for me but when i set tint color it works on Shape Drawable
Drawable background = imageView.getBackground();
background.setTint(getRandomColor())
require android 5.0 API 21
My Kotlin extension function version based on answers above with Compat:
fun Drawable.overrideColor_Ext(context: Context, colorInt: Int) {
val muted = this.mutate()
when (muted) {
is GradientDrawable -> muted.setColor(ContextCompat.getColor(context, colorInt))
is ShapeDrawable -> muted.paint.setColor(ContextCompat.getColor(context, colorInt))
is ColorDrawable -> muted.setColor(ContextCompat.getColor(context, colorInt))
else -> Log.d("Tag", "Not a valid background type")
}
}
The simple way to fill the shape with the Radius is:
(view.getBackground()).setColorFilter(Color.parseColor("#FFDE03"), PorterDuff.Mode.SRC_IN);
May be I am too late.But if you are using Kotlin. There is way like this
var gd = layoutMain.background as GradientDrawable
//gd.setCornerRadius(10)
gd.setColor(ContextCompat.getColor(ctx , R.color.lightblue))
gd.setStroke(1, ContextCompat.getColor(ctx , R.color.colorPrimary)) // (Strokewidth,colorId)
Enjoy....
This might help
1.Set the shape color initially to transparent
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:angle="270"
android:color="#android:color/transparent"/>
<stroke android:width="3dp"
android:color="#FFAA0055"/>
</shape>
Set the shape as a background to the view
Set your preferred color as follows:
Drawable bg = view.getBackground();
bg.setColorFilter(Color.parseColor("#Color"), PorterDuff.Mode.ADD);
I needed to do this in my adapter but the solutions above were either not working or required >= android version 10. The code below worked for me!
val drawable = DrawableCompat.wrap(holder.courseName.background)
DrawableCompat.setTint(drawable, Color.parseColor("#4a1f60"))
For anyone using C# Xamarin, here is a method based on Vikram's snippet:
private void SetDrawableColor(Drawable drawable, Android.Graphics.Color color)
{
switch (drawable)
{
case ShapeDrawable sd:
sd.Paint.Color = color;
break;
case GradientDrawable gd:
gd.SetColor(color);
break;
case ColorDrawable cd:
cd.Color = color;
break;
}
}
The Best way to change Solid color of custom drawable is
For Kotlin.
(findViewById<TextView>(R.id.testing1).getBackground()).setColorFilter(Color.parseColor("#FFDE03"), PorterDuff.Mode.SRC_IN);
We can create this kotlin function.
fun View.updateViewBGSolidColor(colorString: String) {
when (val background: Drawable = this.background) {
is ShapeDrawable -> {
background.paint.color = Color.parseColor(colorString)
}
is GradientDrawable -> {
background.setColor(Color.parseColor(colorString))
}
is ColorDrawable -> {
background.color = Color.parseColor(colorString)
}
}
}
And use it like the below:
yourTextView.updateViewBGSolidColor("#FFFFFF")
GradientDrawable gd = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
new int[] {0xFF616261,0xFF131313});
gd.setCornerRadius(0f);
layout.setBackgroundDrawable(gd);

StateListDrawable and tiled bitmap

This is my custom selector (StateListDrawable)
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="#drawable/common_cell_background" />
<item
android:state_pressed="true"
android:drawable="#drawable/common_cell_background_highlight" />
<item
android:state_focused="true"
android:drawable="#drawable/common_cell_background_highlight" />
<item
android:state_selected="true"
android:drawable="#drawable/common_cell_background_highlight" />
</selector>
Both, common_cell_background and common_cell_background_highlight are XML. Code below:
common_cell_background.xml
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/common_cell_background_bitmap"
android:tileMode="repeat"
android:dither="true">
</bitmap>
common_cell_background_highlight.xml
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/common_cell_background_bitmap_highlight"
android:tileMode="repeat"
android:dither="true">
</bitmap>
Bitmaps are also exactly the same. Highlight is just a little bit lighter and there is no other differences. Both bitmaps are PNG files.
Now I set
convertView.setBackgroundResource(R.drawable.list_item_background);
and here is the problem. My common_cell_background doesn't repeat, it's stretched. But what is suprising when I touch on cell of my list background changes to common_cell_background_highlight and guess what? Everything is fine, it's repeated like it should be. I have no idea where is the problem, why my background doesn't repeat while highlight does. Any thoughts?
This is the bug, it was fixed in ICS, see this answer: https://stackoverflow.com/a/7615120/1037294
Here is a workaround: https://stackoverflow.com/a/9500334/1037294
Note, that the workaround is only applicable for BitmapDrawable, for other types of drawables like StateListDrawable you'll need to do extra work. Here is what I use:
public static void fixBackgrndTileMode(View view, TileMode tileModeX, TileMode tileModeY) {
if (view != null) {
Drawable bg = view.getBackground();
if (bg instanceof BitmapDrawable) {
BitmapDrawable bmp = (BitmapDrawable) bg;
bmp.mutate(); // make sure that we aren't sharing state anymore
bmp.setTileModeXY(tileModeX, tileModeY);
}
else if (bg instanceof StateListDrawable) {
StateListDrawable stateDrwbl = (StateListDrawable) bg;
stateDrwbl.mutate(); // make sure that we aren't sharing state anymore
ConstantState constantState = stateDrwbl.getConstantState();
if (constantState instanceof DrawableContainerState) {
DrawableContainerState drwblContainerState = (DrawableContainerState)constantState;
final Drawable[] drawables = drwblContainerState.getChildren();
for (Drawable drwbl : drawables) {
if (drwbl instanceof BitmapDrawable)
((BitmapDrawable)drwbl).setTileModeXY(tileModeX, tileModeY);
}
}
}
}
}

Is it possible to have an animated drawable?

Is it possible to create a drawable that has some sort of animation, whether it is a frame by frame animation, rotation, etc, that is defined as a xml drawable and can be represented by a single Drawable object without having to deal with the animation in code?
How I am thinking to use it:
I have a list and each item in this list may at sometime have something happening to it. While it is happening, I would like to have a spinning progress animation similar to a indeterminate ProgressBar. Since there may also be several of these on screen I thought that if they all shared the same Drawable they would only need one instance of it in memory and their animations would be synced so you wouldn't have a bunch of spinning objects in various points in the spinning animation.
I'm not attached to this approach. I'm just trying to think of the most efficient way to display several spinning progress animations and ideally have them synced together so they are consistent in appearance.
Thanks
In response to Sybiam's answer:
I have tried implementing a RotateDrawable but it is not rotating.
Here is my xml for the drawable so far:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="#drawable/my_drawable_to_rotate"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="800"
android:visible="true" />
I have tried using that drawable as the src and background of a ImageView and both ways only produced a non-rotating image.
Is there something that has to start the image rotation?
Yes! The (undocumented) key, which I discovered by reading the ProgressBar code is that you have to call Drawable.setLevel() in onDraw() in order for the <rotate> thing to have any effect. The ProgressBar works something like this (extra unimportant code omitted):
The drawable XML:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<rotate
android:drawable="#drawable/spinner_48_outer_holo"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="0"
android:toDegrees="1080" />
</item>
<item>
<rotate
android:drawable="#drawable/spinner_48_inner_holo"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="720"
android:toDegrees="0" />
</item>
</layer-list>
In onDraw():
Drawable d = getDrawable();
if (d != null)
{
// Translate canvas so a indeterminate circular progress bar with
// padding rotates properly in its animation
canvas.save();
canvas.translate(getPaddingLeft(), getPaddingTop());
long time = getDrawingTime();
// I'm not sure about the +1.
float prog = (float)(time % ANIM_PERIOD+1) / (float)ANIM_PERIOD;
int level = (int)(MAX_LEVEL * prog);
d.setLevel(level);
d.draw(canvas);
canvas.restore();
ViewCompat.postInvalidateOnAnimation(this);
}
MAX_LEVEL is a constant, and is always 10000 (according to the docs).
ANIM_PERIOD is the period of your animation in milliseconds.
Unfortunately since you need to modify onDraw() you can't just put this drawable in an ImageView since ImageView never changes the drawable level. However you may be able to change the drawable level from outside the ImageView's. ProgressBar (ab)uses an AlphaAnimation to set the level. So you'd do something like this:
mMyImageView.setImageDrawable(myDrawable);
ObjectAnimator anim = ObjectAnimator.ofInt(myDrawable, "level", 0, MAX_LEVEL);
anim.setRepeatCount(ObjectAnimator.INFINITE);
anim.start();
It might work but I haven't tested it.
Edit
There is actually an ImageView.setImageLevel() method so it might be as simple as:
ObjectAnimator anim = ObjectAnimator.ofInt(myImageVew, "ImageLevel", 0, MAX_LEVEL);
anim.setRepeatCount(ObjectAnimator.INFINITE);
anim.start();
Drawables
There you go! And this one for RotateDrawable. I believe that from the Doc it should be pretty straitght forward. You can define everything in a xml file and set the background of a view as the drawable xml. /drawable/myrotate.xml -> #drawable/myrotate
Edit:
This is an answer I found here.
Drawable Rotating around its center Android
Edit 2:
You are right the RotateDrawable seem broken. I don't know I tried it too. I haven't yet succeded in making it animate. But I did succed to rotate it. You have to use setLevel which will rotate it. Though it doesn't look really useful. I browsed the code and the RotateDrawable doesn't even inflate the animation duration and the current rotation seems strangely use the level as a measure for rotation. I believe you have to use it with a AnimationDrawable but here again. It just crashed for me. I haven't used that feature yet but planned to use it in the future. I browsed the web and the RotateDrawable seems to be very undocumented like almost every Drawable objects.
Here is one of possible ways (especially useful when you have a Drawable somewhere set and need to animate it). The idea is to wrap the drawable and decorate it with animation. In my case, I had to rotate it, so below you can find sample implementation:
public class RotatableDrawable extends DrawableWrapper {
private float rotation;
private Rect bounds;
private ObjectAnimator animator;
private long defaultAnimationDuration;
public RotatableDrawable(Resources resources, Drawable drawable) {
super(vectorToBitmapDrawableIfNeeded(resources, drawable));
bounds = new Rect();
defaultAnimationDuration = resources.getInteger(android.R.integer.config_mediumAnimTime);
}
#Override
public void draw(Canvas canvas) {
copyBounds(bounds);
canvas.save();
canvas.rotate(rotation, bounds.centerX(), bounds.centerY());
super.draw(canvas);
canvas.restore();
}
public void rotate(float degrees) {
rotate(degrees, defaultAnimationDuration);
}
public void rotate(float degrees, long millis) {
if (null != animator && animator.isStarted()) {
animator.end();
} else if (null == animator) {
animator = ObjectAnimator.ofFloat(this, "rotation", 0, 0);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
}
animator.setFloatValues(rotation, degrees);
animator.setDuration(millis).start();
}
#AnimatorSetter
public void setRotation(float degrees) {
this.rotation = degrees % 360;
invalidateSelf();
}
/**
* Workaround for issues related to vector drawables rotation and scaling:
* https://code.google.com/p/android/issues/detail?id=192413
* https://code.google.com/p/android/issues/detail?id=208453
*/
private static Drawable vectorToBitmapDrawableIfNeeded(Resources resources, Drawable drawable) {
if (drawable instanceof VectorDrawable) {
Bitmap b = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
drawable.setBounds(0, 0, c.getWidth(), c.getHeight());
drawable.draw(c);
drawable = new BitmapDrawable(resources, b);
}
return drawable;
}
}
and you can use it like this (rotating toolbar navigation icon 360 degrees):
backIcon = new RotatableDrawable(getResources(), toolbar.getNavigationIcon().mutate());
toolbar.setNavigationIcon(backIcon);
backIcon.rotate(360);
It shouldn't be hard to add a method that will rotate it indefinite (setRepeatMode INFINITE for animator)
You can start from studying the ProgressBar2 from API Demos project (it is available as a part of the SDK). Specifically pay attention to R.layout.progressbar_2.
I take back to life this post just to post my solution with vector drawable:
So you need 1 vector drawable in drawable resource (#drawable/ic_brush_24dp):
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<group
android:name="rotation" <---- target name of animated-vector
android:pivotX="12.0"
android:pivotY="12.0"
android:rotation="0.0"> <--- propertyName of animator
<path
android:fillColor="#FF000000"
android:pathData="M7,14c-1.66,0 -3,1.34 -3,3 0,1.31 -1.16,2 -2,2 0.92,1.22 2.49,2 4,2 2.21,0 4,-1.79 4,-4 0,-1.66 -1.34,-3 -3,-3zM20.71,4.63l-1.34,-1.34c-0.39,-0.39 -1.02,-0.39 -1.41,0L9,12.25 11.75,15l8.96,-8.96c0.39,-0.39 0.39,-1.02 0,-1.41z" />
</group>
</vector>
Then you need your animator in animator resource folder (#animator/pendulum)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="350"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:propertyName="rotation"
android:valueFrom="0.0"
android:valueTo="-90.0" />
</set>
Then you need your animated-vector in drawable resource (#drawable/test_anim_brush2):
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="#drawable/ic_brush_24dp">
<target
android:name="rotation"
android:animation="#animator/pendulum" />
</animated-vector>
Then you need to extend ImageView (because that's the only way i found to start the animation)
public class ImageView extends AppCompatImageView{
public ImageView(Context context){
super(context);
init(context, null, 0);
}
public ImageView(Context context, AttributeSet attrs){
super(context, attrs);
init(context, attrs, 0);
}
public ImageView(Context context, AttributeSet attrs, int defStyleAttr){
super(context, attrs, defStyleAttr);
init(context, attrs, 0);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr){
}
#Override
protected void onAttachedToWindow(){
super.onAttachedToWindow();
Drawable d = getBackground();
if(d instanceof AnimatedVectorDrawable){
AnimatedVectorDrawable anim = (AnimatedVectorDrawable)d;
anim.start();
}
}
#Override
protected void onDetachedFromWindow(){
super.onDetachedFromWindow();
Drawable d = getBackground();
if(d instanceof AnimatedVectorDrawable){
AnimatedVectorDrawable anim = (AnimatedVectorDrawable)d;
anim.stop();
}
}
}
And then add your imageView to your layout :
<ui.component.ImageView
android:id="#+id/test_anim_brush"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:background="#drawable/test_anim_brush2"/>
Pro :
You can fully define your animation in xml with object animator (duration, interpolator, etc...)
Works with everything which accept drawable (as long as you add at good place the start animator)
Con:
Works only with vector
Still need to add your custom start by extending class or whenever you think it is smart...
private ValueAnimator rotateDrawable(RotateDrawable drawable, int fromDegree, int toDegree) {
drawable.setFromDegrees(fromDegree);
drawable.setToDegrees(toDegree);
return ObjectAnimator.ofInt(drawable, "level", 0, 10000);
}
level is the interpulting value from 0 to 100000. the actual animation values are set by the setter methods
you can use stateListAnimator
<ImageView
android:id="#+id/your_id"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="#drawable/your_drawable"
android:stateListAnimator="#anim/bounce" />
and bounce
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/bounce">
<translate
android:duration="900"
android:fromXDelta="100%p"
android:toXDelta="0%p" />
</set>

Categories

Resources