章节来自《Android开发艺术探索》
第一种方式
3.2.2 使用动画
上一节介绍了采用scrollTo/scrollBy来实现View的滑动,本节介绍另外一种滑动方式,即使用动画,通过动画我们能够让一个View进行平移,而平移就是一种滑动。使用动画来移动View,主要是操作View的translationX和translationY属性,既可以采用传统的View动画,也可以采用属性动画,如果采用属性动画的话,为了能够兼容3.0以下的版本,需要采用开源动画库nineoldandroids(http://nineoldandroids.com/)。
采用View动画的代码,如下所示。此动画可以在100ms内将一个View从原始位置向右下角移动100个像素。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:zAdjustment="normal" >
<translate
android:duration="100"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/linear_interpolator"
android:toXDelta="100"
android:toYDelta="100" />
</set>
在res/下创建anim目录,再创建animation_test.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true" android:zAdjustment="normal" > <!--默认为@android:anim/accelerate_decelerate_interpolator,即加速减速插值器,--> <!--android:duration="10000" 10秒,为了看出速度先快后慢,是使用默认插值器的效果--> <translate android:duration="5000" android:fromXDelta="0" android:fromYDelta="0" android:interpolator="@android:anim/linear_interpolator" android:toXDelta="500" android:toYDelta="500" /> </set>
MainActivity.java
import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.TextView; public class MainActivity extends AppCompatActivity { TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.tv); textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Animation animation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.animation_test); textView.startAnimation(animation); } }); } }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/tv" android:text="click me" android:background="@color/colorPrimary" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
效果
注意:
上面提到View动画并不能真正改变View的位置,这会带来一个很严重的问题。试想一下,比如我们通过View动画将一个Button向右移动100px,并且这个View设置的有单击事件,然后你会惊奇地发现,单击新位置无法触发onClick事件,而单击原始位置仍然可以触发onClick事件,尽管Button已经不在原始位置了。这个问题带来的影响是致命的,但是它却又是可以理解的,因为不管Button怎么做变换,但是它的位置信息(四个顶点和宽/高)并不会随着动画而改变,因此在系统眼里,这个Button并没有发生任何改变,它的真身仍然在原始位置。在这种情况下,单击新位置当然不会触发onClick事件了,因为Button的真身并没有发生改变,在新位置上只是View的影像而已。基于这一点,我们不能简单地给一个View做平移动画并且还希望它在新位置继续触发一些单击事件。
从Android 3.0开始,使用属性动画可以解决上面的问题,但是大多数应用都需要兼容到Android 2.2,在Android 2.2上无法使用属性动画,因此这里还是会有问题。那么这种问题难道就无法解决了吗?也不是的,虽然不能直接解决这个问题,但是还可以间接解决这个问题,这里给出一个简单的解决方法。针对上面View动画的问题,我们可以在新位置预先创建一个和目标Button一模一样的Button,它们不但外观一样连onClick事件也一样。当目标Button完成平移动画后,就把目标Button隐藏,同时把预先创建的Button显示出来,通过这种间接的方式我们解决了上面的问题。这仅仅是个参考,面对这种问题时读者可以灵活应对。
第二种方式
如果采用属性动画的话,就更简单了,以下代码可以将一个View在100ms内从原始位置向右平移100像素。
ObjectAnimator.ofFloat(targetView,"translationX",0,100).setDuration
(100).start();
修改MainActivity.java
package com.example.wuf.overdrawtest; import android.animation.ObjectAnimator; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.TextView; public class MainActivity extends AppCompatActivity { TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.tv); textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Animation animation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.animation_test); // textView.startAnimation(animation); ObjectAnimator.ofFloat(textView,"translationX",0,500).setDuration (5000).start(); ObjectAnimator.ofFloat(textView,"translationY",0,500).setDuration (5000).start(); } }); } }
效果: