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

给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>
阿神
阿神

闭关修行中......

membalas semua(1)
Ty80

Masalahnya terletak pada panggilan performAnimate() ObjectAnimator.ofInt(...) Disebabkan masalah pelaksanaan ObjectAnimator itu sendiri, ia akan menyimpan sasaran sebagai jenis WeakReference adalah seperti berikut:

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

Atas sebab ini, jika tika objek tidak dikekalkan, ia berkemungkinan dikitar semula oleh gc Oleh itu, ViewWrapper harus digunakan sebagai pembolehubah ahli kelas untuk mengelakkannya daripada dikitar semula

Selain itu, jika anda terus menekan, berbilang permintaan animasi akan terus dihasilkan Animasi yang belum selesai dari kali terakhir dan kali terakhir (terakhir...kali terakhir) akan menjejaskan tindakan animasi semasa memenuhi keperluan yang diharapkan, anda harus membatalkan permintaan animasi terakhir Kodnya adalah seperti berikut:

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();
}
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan