android - 對button的width屬性做屬性動畫時出錯
問題描述
給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: android:layout_width='match_parent' android:layout_height='match_parent' android:orientation='vertical' tools:context='com.example.circleview.MainActivity'> <Buttonandroid: android:layout_width='wrap_content'android:layout_height='50dp'android:text='Property Animation' /> <TextViewandroid: android:layout_width='wrap_content'android:layout_height='wrap_content'android:text='please click the button' /></LinearLayout>
問題解答
回答1:問題就出在 performAnimate() 的 ObjectAnimator.ofInt(...) 調用, 由于 ObjectAnimator 本身實現的問題, 它會把 target 存為 WeakReference 類型. 關鍵代碼如下:
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);}@Overridepublic 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 startingmInitialized = false; }}
由于這個原因, 如果不保持對象實例, 那么就很有可能會被gc回收掉. 因此, ViewWrapper 應該作為類成員變量, 以防被回收.
另外, 如果不停地按, 就會不停地產生多個動畫請求. 而上次以及上上次(上...上次)未執行完成的動畫會影響當次的動畫動作. 如果要達到預期的要求, 就應該把上次的動畫請求取消掉. 代碼如下:
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();}
相關文章:
1. python - 數據與循環次數對應不上2. mysql - 把一個表中的數據count更新到另一個表里?3. 請教使用PDO連接MSSQL數據庫插入是亂碼問題?4. mysql - 分庫分表、分區、讀寫分離 這些都是用在什么場景下 ,會帶來哪些效率或者其他方面的好處5. Python爬蟲如何爬取span和span中間的內容并分別存入字典里?6. 視頻文件不能播放,怎么辦?7. mysql 查詢身份證號字段值有效的數據8. python - 爬蟲模擬登錄后,爬取csdn后臺文章列表遇到的問題9. node.js - nodejs開發中常用的連接mysql的庫10. 黑客 - Python模塊安全權限
