android - 对button的width属性做属性动画时出错
阿神
阿神 2017-04-18 09:05:12
0
1
473

给button写了一个包装类,设置setWidth()和getWidth()方法,大多时候动画运行是正确的,但是当我连续运行几次之后就出错了,目的是把button的宽度从500px通过动画变成800px

运行几次后, 动画执行完成后button的宽度未设置为800, 如下图:

这是代码

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private TextView textView;
    private Button button;
    private int clickTimes = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.click);
        textView = (TextView) findViewById(R.id.tv_showWidth);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                performAnimate();
                clickTimes ++;
                ViewTreeObserver observer = button.getViewTreeObserver();
                observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        textView.setText("The " + (clickTimes) + "th click" + "button's width:" + button.getWidth());
                    }
                });
            }
        });
    }

    private void performAnimate() {
        ViewWrapper viewWrapper = new ViewWrapper(button);
        ObjectAnimator.ofInt(viewWrapper, "width", 500, 800).setDuration(1000).start();
    }

    private static class ViewWrapper {
        private View mTarget;

        public ViewWrapper(View mTarget) {
            this.mTarget = mTarget;
        }

        public int getWidth() {
            return mTarget.getLayoutParams().width;
        }

        public void setWidth(int width) {
            mTarget.getLayoutParams().width = width;
            mTarget.requestLayout(); //长度宽度改变需要调用此方法进行view的测量、布局和绘制
            Log.d(TAG, "setWidth: " + mTarget.getWidth());
        }
    }

}

layout 文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.circleview.MainActivity">

    <Button
        android:id="@+id/click"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:text="Property Animation" />

    <TextView
        android:id="@+id/tv_showWidth"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="please click the button" />

</LinearLayout>
阿神
阿神

闭关修行中......

répondre à tous(1)
Ty80

Le problème réside dans l'appel performAnimate() de ObjectAnimator.ofInt(...) En raison du problème d'implémentation de ObjectAnimator lui-même, il enregistrera la cible sous le type WeakReference. Le code clé est le suivant :

.
public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
    ObjectAnimator anim = new ObjectAnimator(target, propertyName);
    anim.setIntValues(values);
    return anim;
}

private ObjectAnimator(Object target, String propertyName) {
    setTarget(target);
    setPropertyName(propertyName);
}

@Override
public void setTarget(@Nullable Object target) {
    final Object oldTarget = getTarget();
    if (oldTarget != target) {
        if (isStarted()) {
            cancel();
        }
        mTarget = target == null ? null : new WeakReference<Object>(target);
        // New target should cause re-initialization prior to starting
        mInitialized = false;
    }
}

Pour cette raison, si l'instance d'objet n'est pas maintenue, elle est susceptible d'être recyclée par gc. Par conséquent, ViewWrapper doit être utilisée comme variable membre de classe pour empêcher son recyclage.

De plus, si vous continuez à appuyer, plusieurs demandes d'animation continueront à être générées. Les animations inachevées de la dernière fois et de la dernière fois (dernière...dernière fois) affecteront l'action d'animation en cours. répond aux exigences attendues, vous devez annuler la dernière demande d'animation. Le code est le suivant :

.

private ObjectAnimator mObjectAnimator;
private ViewWrapper viewWrapper;

private void performAnimate() {
    if (mObjectAnimator != null) {
        mObjectAnimator.cancel();
        mObjectAnimator = null;
    }

    viewWrapper = new ViewWrapper(button);
    mObjectAnimator = ObjectAnimator.ofInt(viewWrapper, "width", 500, 800).setDuration(1000);
    mObjectAnimator.start();
}
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal