web-dev-qa-db-ja.com

AndroidのVectorDrawableアニメーションを正確に制御

PDATE:解決策が見つかりました!下にスクロールして、受け入れた回答を確認してください。

1つの画像の複数の要素をアニメーション化し、アニメーションをViewPagersの位置にリンクしたい(したがって、ドラッグされている現在のページに応じて、複数の要素がモーフィングまたはフライイン/フライアウトします)。

それで、アニメーションの現在のフレームを正確に制御する方法はありますか?たとえば、次のセットがあるとします。

_<?xml version="1.0" encoding="utf-8"?>
<set xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <objectAnimator
        Android:interpolator="@Android:anim/decelerate_interpolator"
        Android:duration="800"
        Android:propertyName="scaleY"
        Android:valueFrom="0"
        Android:valueTo="1" />
    <objectAnimator
        Android:interpolator="@Android:anim/decelerate_interpolator"
        Android:duration="800"
        Android:propertyName="scaleX"
        Android:valueFrom="0"
        Android:valueTo="1" />
    <objectAnimator
        Android:interpolator="@Android:anim/decelerate_interpolator"
        Android:duration="800"
        Android:propertyName="rotation"
        Android:valueFrom="0"
        Android:valueTo="360" />
</set>
_

アニメーションベクトルファイル:

_<animated-vector xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:drawable="@drawable/pre_signup_1" >
    <target
        Android:name="plus_button"
        Android:animation="@anim/pre_signup_1_plus_container" />
    <target
        Android:name="plus"
        Android:animation="@anim/pre_signup_1_plus_sign" />
</animated-vector>
_

アニメーションを実行するためのJavaコード:

_ImageView mImage1 = (ImageView) findViewById(R.id.image_1);
AnimatedVectorDrawableCompat animated = (AnimatedVectorDrawableCompat) mImage1.getDrawable();

animated.start();
_

おそらくアニメーションの現在の状態を半分に設定するsetCurrentDuration(400)のようなアニメーションを制御する方法はありますか?多分そのベクタードローアブルをレイヤーに分割し、それらをプログラムでアニメーション化する方法はありますか?前もって感謝します!

21
Arthur

VectorDrawableCompat内のパスとグループにアクセスして、好きなようにアニメーション化/モーフィングすることが可能のようです。

いくつかの調査の後、Android.support.graphics.drawableパッケージから次のクラスを複製することになりました:AndroidResourcesPathParserTypedArrayUtilsVectorDrawableCommonおよびVectorDrawableCompat

次に、VectorDrawableCompatクラス内でgetTargetByNameVGroupおよびVFullPathのメソッドとクラスをパブリックにする必要があります。

次にVectorDrawableCompatクラスでAndroid version(Build.VERSION.SDK_INT >= 23)をチェックするブロックを削除します。理由はわかりませんが、行わない場合は、アニメーションはAndroid API 23以降では機能しません(さらに調査が必要です)。

私はいくつかのプライベートメソッドを見逃したかもしれませんが、問題が発生した場合はそれらを公開するだけです。

これで、VectorDrawableのレイヤーにアクセスできるようになりました。 ViewPagerの位置に応じてベクトルグループをスケーリングする小さな例を次に示します。

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:width="276dp"
    Android:height="359dp"
    Android:viewportWidth="276"
    Android:viewportHeight="359">

    <group
        Android:pivotX="205.5"
        Android:pivotY="214.5"
        Android:name="my_group">
        <path
            Android:strokeColor="#4D394B"
            Android:strokeWidth="7"
            Android:strokeLineJoin="bevel"
            Android:fillColor="#1ED761"
            Android:pathData="M206.5,180 C186.9,180,171,195.9,171,215.5 S186.9,251,206.5,251
C226.1,251,242,235.1,242,215.5 S226.1,180,206.5,180 Z" />
        <path
            Android:fillColor="#4D394B"
            Android:pathData="M210,211 L210,190 L202,190 L202,211 L181,211 L181,219 L202,219 L202,241 L210,241
L210,219 L232,219 L232,211 Z" />
    </group>
</vector>

そして、これはグループをアニメーション化するために使用されるコードです:

ImageView myImageView;
VectorDrawableCompat.VGroup myVectorGroup;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_welcome);

    myImageView = (ImageView) findViewById(R.id.image_1);

    VectorDrawableCompat vectorDrawable = VectorDrawableCompat.create(getResources(), R.drawable.my_vector_drawable, null);
    vectorDrawable.setAllowCaching(false); // Important to allow image updates
    myVectorGroup = (VectorDrawableCompat.VGroup) vectorDrawable.getTargetByName("my_group");

    myImageView.setImageDrawable(vectorDrawable);

    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if(myVectorGroup != null && position < 1) {
                myVectorGroup.setScaleX(1f - positionOffset);
                myVectorGroup.setScaleY(1f - positionOffset);

                myImageView.invalidate();
            }
        }
    });
}

互換性を確認するにはさらにテストが必要ですが、今のところ機能します!

12
Arthur

AnimatedVectorDrawable/AnimatedVectorDrawableCompatを使用してプログラムでこれを行うことはできないと思います。

回避策は、 レベルリストドローアブル を使用し、そのレベルをアニメーション化することです。ただし、レベルには多くの画像が必要です。スムーズな移行をシミュレートするために、ここでは3つのレベルだけを使用してデモを行っています。

まず、次のようにドローアブルレベルリストを定義します:res/drawable/my_level_list.xml

<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:Android="http://schemas.Android.com/apk/res/Android">
<item Android:drawable="@drawable/level0"
    Android:maxLevel="0"/>
    <item Android:drawable="@drawable/level1"
        Android:maxLevel="1"/>

    <item Android:drawable="@drawable/level2"
        Android:maxLevel="2"/>
</level-list>

次に、レイアウトファイルで:

<ImageView
        Android:id="@+id/img"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_centerInParent="true"
        Android:src="@drawable/my_level_list" />

それからあなたの活動で:

int MIN_LEVEL=0;
int MAX_LEVEL=2;

ImageView img=(ImageView)findViewById(R.id.img);

Drawable myLevelSetDrawable= img.getDrawable();
ObjectAnimator anim=ObjectAnimator.ofInt(myLevelSetDrawable,"level",MIN_LEVEL,MAX_LEVEL);
anim.setInterpolator(new BounceInterpolator());
AnimatorSet set=new AnimatorSet();
set.play(anim);
set.setDuration(1000);
set.start();

お役に立てば幸いです。

2
Mina Samy

ドキュメントがAnimatedVectorDrawablesについて述べている限り、アニメーションの状態を追跡したり、animationStartとanimationEnd以外の状態にジャンプしたりする方法はありません。

この効果を実現するには、カスタムソリューションを使用する必要がある場合があります。 このブログ投稿 Androidのウィジェット状態追跡を使用して同様の効果を実現する方法を説明しています。

1
Rafay Ali