Возможно ли иметь анимированный рисунок? - PullRequest
8 голосов
/ 11 января 2011

Можно ли создать чертеж, который имеет некоторую анимацию, будь то покадровая анимация, вращение и т. Д., Который определяется как чертеж в формате xml и может быть представлен одним объектом Drawable без необходимости обрабатывать с анимацией в коде?

Как я думаю использовать это: У меня есть список, и с каждым элементом в этом списке может что-то происходить. Пока это происходит, я бы хотел, чтобы анимация прогресса была похожа на неопределенный ProgressBar. Поскольку на экране также может быть несколько таких объектов, я подумал, что если бы они все использовали один и тот же Drawable, им потребовался бы только один его экземпляр в памяти, и их анимация была бы синхронизирована, чтобы у вас не было связки вращающихся объектов в разных точках. в вращающейся анимации.

Я не привязан к этому подходу. Я просто пытаюсь придумать наиболее эффективный способ отображения нескольких вращающихся анимаций прогресса и в идеале синхронизировать их, чтобы они выглядели согласованно.

Спасибо

В ответ на ответ Сибиама:

Я пытался реализовать RotateDrawable, но он не вращается.

Вот мой xml для прорисовки до сих пор:

<?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" />

Я пытался использовать этот объект в качестве источника и фона для ImageView, и оба способа создавали только невращающееся изображение.

Есть ли что-то, что должно начать вращение изображения?

Ответы [ 6 ]

16 голосов
/ 21 ноября 2012

Да! Ключ (недокументированный), который я обнаружил, читая код ProgressBar, заключается в том, что вам нужно вызвать Drawable.setLevel() в onDraw(), чтобы вещь <rotate> имела какой-либо эффект. ProgressBar работает примерно так (дополнительный неважный код пропущен):

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 - это константа, которая всегда равна 10000 (согласно документам). ANIM_PERIOD - это период вашей анимации в миллисекундах.

К сожалению, так как вам нужно изменить onDraw(), вы не можете просто поместить это рисование в ImageView, так как ImageView никогда не изменяет уровень рисования. Однако вы можете изменить уровень рисования с за пределами ImageView. ProgressBar (ab) использует AlphaAnimation для установки уровня. Итак, вы бы сделали что-то вроде этого:

mMyImageView.setImageDrawable(myDrawable);

ObjectAnimator anim = ObjectAnimator.ofInt(myDrawable, "level", 0, MAX_LEVEL);
anim.setRepeatCount(ObjectAnimator.INFINITE);
anim.start();

Может сработать, но я не проверял.

Редактировать

На самом деле существует метод ImageView.setImageLevel(), поэтому он может быть таким простым:

ObjectAnimator anim = ObjectAnimator.ofInt(myImageVew, "ImageLevel", 0, MAX_LEVEL);
anim.setRepeatCount(ObjectAnimator.INFINITE);
anim.start();
7 голосов
/ 11 января 2011

* 1002 вводимого коэффициента *

Вот, пожалуйста! И этот для RotateDrawable . Я считаю, что от Дока это должно быть довольно прямолинейно. Вы можете определить все в xml-файле и установить фон представления как нарисованный xml. /drawable/myrotate.xml -> @ drawable / myrotate

Edit: Это ответ, который я нашел здесь. Drawable Вращающийся вокруг его центра Android

Редактировать 2: Вы правы, RotateDrawable кажется сломанным. Я не знаю, я тоже попробовал. Мне пока не удалось оживить его. Но мне удалось повернуть его. Вы должны использовать setLevel, который будет вращать его. Хотя это не выглядит действительно полезным. Я просмотрел код, и RotateDrawable даже не увеличивает продолжительность анимации, и текущее вращение кажется странным образом использует уровень в качестве меры для вращения. Я считаю, что вы должны использовать его с AnimationDrawable, но здесь снова. Это просто разбилось для меня. Я еще не использовал эту функцию, но планировал использовать ее в будущем. Я просматривал Интернет, и RotateDrawable, похоже, очень недокументирован, как почти все объекты Drawable.

2 голосов
/ 23 августа 2016

Вот один из возможных способов (особенно полезен, когда у вас есть набор Drawable где-то и вам нужно его анимировать). Идея состоит в том, чтобы обернуть нарисованное и украсить его анимацией. В моем случае мне пришлось повернуть его, поэтому ниже вы можете найти пример реализации:

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;
    }
}

и вы можете использовать его следующим образом (вращающийся значок панели инструментов на 360 градусов):

backIcon = new RotatableDrawable(getResources(), toolbar.getNavigationIcon().mutate());
toolbar.setNavigationIcon(backIcon);
backIcon.rotate(360);

Не должно быть сложно добавить метод, который будет вращать его неопределенно (setRepeatMode INFINITE for animator)

1 голос
/ 11 января 2011

Вы можете начать с изучения ProgressBar2 из проекта API Demos (доступно как часть SDK). Особо обратите внимание на R.layout.progressbar_2.

0 голосов
/ 06 января 2018

вы можете использовать stateListAnimator

    <ImageView
        android:id="@+id/your_id"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:src="@drawable/your_drawable"
        android:stateListAnimator="@anim/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>
0 голосов
/ 09 августа 2017
private ValueAnimator rotateDrawable(RotateDrawable drawable, int fromDegree, int toDegree) {
    drawable.setFromDegrees(fromDegree);
    drawable.setToDegrees(toDegree);
    return ObjectAnimator.ofInt(drawable, "level", 0, 10000);
}

level - это значение от 0 до 100000. Фактические значения анимации устанавливаются методами установки

...