Возможность рисования вокруг своего центра Android

Я получаю странные результаты со следующим кодом:

iv = (ImageView) findViewById(R.id.iv);
        iv.setImageResource(R.drawable.spinner_white_76);

        Animation a = new RotateAnimation(0.0f, 360.0f,
                Animation.RELATIVE_TO_SELF, iv.getDrawable()
                        .getIntrinsicWidth() / 2, Animation.RELATIVE_TO_SELF,
                iv.getDrawable().getIntrinsicHeight() / 2);
        a.setRepeatCount(-1);
        a.setDuration(1000);

        iv.startAnimation(a);

Каков правильный способ указания точки оси (центр рисования)?

Ответ 1

Чувствуйте себя глупо! Получил это, чтобы работать, потратив некоторое время на тщательное чтение документации:

Animation a = new RotateAnimation(0.0f, 360.0f,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        a.setRepeatCount(-1);
        a.setDuration(1000);

Ответ 2

Обратите внимание, что это не будет работать, если ваш объект имеет асимметричное дополнение (например, левое дополнение 5px и правое заполнение 0px), поскольку заполнение считается частью объекта. Это означает, что вычисленный центр будет смещен.

Одним из решений этого является использование полей вместо заполнения, если вы используете дополнение для макета. Поскольку API говорит о границах: "Это пространство находится за пределами этой границы взглядов". (ViewGroup.MarginLayoutParams)

Это означает, что поля не будут вращаться по мере заполнения.

Ответ 3

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

Я закончил писать пользовательские drawable, которые могут обернуть любой 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;
    }
}