在生活中咱们应用 Android 的 App 常常会看到一些炫丽的动静界面,呈现这种成果很多是因为 View 的滑动,比方 RecyclerView 的滑动,把握 View 的滑动形式,咱们也能做出这样的成果;实现 View 的滑动常见的有4种办法,它们别离是 应用 scrollTo/scrollBy、应用动画、扭转布局参数和应用 layout,上面将对它们一一进行介绍。

1、应用 scrollTo/scrollBy
View提供了 scrollTo(int x,int y) 和 scrollBy(int x,int y) 这两个办法实现了它的滑动,具体实现代码(基于 Android Api 27)如下所示:

public void scrollTo(int x, int y) {  if (mScrollX != x || mScrollY != y) {    int oldX = mScrollX;    int oldY = mScrollY;    mScrollX = x;    mScrollY = y;    invalidateParentCaches();    onScrollChanged(mScrollX, mScrollY, oldX, oldY);    if (!awakenScrollBars()) {        postInvalidateOnAnimation();    }   } }public void scrollBy(int x, int y) {  scrollTo(mScrollX + x, mScrollY + y);}

从scrollTo(int x,int y) 和 scrollBy(int x,int y) 这两个办法总结得出,scrollTo(int x,int y) 实现了所传递参数的相对滑动,而 scrollBy(int x,int y) 实现了以后地位的绝对滑动,因为它调用了 scrollTo(int x,int y) 办法。在这2个办法中,呈现了 mScrollX 和 mScrollY 这两个成员变量,其中 mScrollX 示意 View 的左边缘和 View 内容左边缘在程度方向的间隔,mScrollY 示意 View 上边缘和 View 内容上边缘在垂直方向上的间隔。上面写一个例子来应用 scrollBy(int x,int y) 办法;首先新建一个布局文件 activity_view_general_slide.xml,它的代码如下所示:

<?xml version="1.0" encoding="utf-8"?><LinearLayout        xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.example.administrator.androidart.activites.ViewGeneralSlideActivity"><TextView android:id="@+id/tv_scroll" android:layout_width="match_parent" android:layout_marginTop="20px" android:text="scrollBy滑动" android:background="#00FF00" android:onClick="onClickView" android:gravity="bottom" android:layout_height="match_parent" /></LinearLayout>

而后再新建一个Java文件,名字为 ViewGeneralSlideActivity,代码如下所示:

private TextView mTv;private MyHandler mHandler = null;private int mSlideY = 20;private int mSlideX = 20;private MyThread thread = null;private boolean isRunThread = true;class MyHandler extends Handler {   @Override   public void handleMessage(Message msg) {      super.handleMessage(msg);      mTv.scrollBy(0,mSlideY);      mSlideY += 10;   } }@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_view_general_slide);    mTv = findViewById(R.id.tv_scroll);    mHandler = new MyHandler();    thread = new MyThread();}public void onClickView(View view) {    thread.start();}class MyThread extends Thread {    @Override    public void run() {        super.run();        while (isRunThread) {           try {               Thread.sleep(500);               sendMessage();           } catch (InterruptedException e) {               e.printStackTrace();           }        }      }  }@Overrideprotected void onDestroy() {     super.onDestroy();     isRunThread = false;     if (mHandler != null) {          mHandler.removeCallbacksAndMessages(null);     } }  private void sendMessage() {     Message message = Message.obtain();     mHandler.sendMessage(message); } 

没点击“scrollBy滑动”控件之前的成果如下所示:

点击“scrollBy滑动”控件之后的成果如下所示:

留神:不论是 scrollBy(int x,int y) 还是 scrollTo(int x,int y) 办法,滑动的并非是 View 自身,而是 View 的内容。

2、应用动画

应用动画来挪动 View ,是通过 View 的 translationX 和 translationY 这两个属性来实现的,它即能够采纳传统的 View 动画,也能够采纳属性动画;在应用属性动画方面,如果要在 Android 3.0以下版本应用,那么就要应用到开源动画库 nineoldandroids,它的官网地址为:http://nineoldandroids.com/ 。上面举个例子用代码实现应用 View 动画来挪动。

2、1 采纳传统的 View 动画

(1) 在 res 目录新建 anim 文件夹并在 anim 文件夹下创立 view_translate.xml:

<?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:fromXDelta="0"   android:fromYDelta="0"   android:toXDelta="200"   android:toYDelta="200"   android:duration="3000"   /></set> 

(2) 新建一个 Java 文件,名字叫 AnimationActivity,并实现它的代码,如下所示:

private TextView mTv;@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_animation);    mTv = findViewById(R.id.tv);}public void onClick(View view) {    Animation animation = AnimationUtils.loadAnimation(this, R.anim.view_translate);    mTv.startAnimation(animation);}

(3) 在 layout 文件夹下新建一个 activity_animation.xml 文件,代码如下所示:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="demo1.xe.com.myapplication2.AnimationActivity">     <Button android:layout_width="match_parent"     android:text="点击该按钮可挪动view"     android:onClick="onClick"     android:layout_height="wrap_content" />     <TextView android:id="@+id/tv"     android:layout_width="300px"     android:gravity="center"     android:text="可挪动的传统view"     android:background="#FF0000"     android:layout_height="wrap_content" /></LinearLayout>

没点击 “点击该按钮可挪动view” 这个按钮之前,它运行的效果图如下所示:

点击 “点击该按钮可挪动view” 这个按钮之后,它运行时挪动的过程中,某一瞬间的效果图如下所示:

2、2 应用属性动画挪动

(1) 为了兼容 Android 3.0 以下版本的手机,在我的项目 app 目录下的 build.gradle文件中增加 nineoldandroids 的依赖:

implementation 'com.nineoldandroids:library:2.4.0'

(2) 新建一个 Java 文件,名字叫 Animation2Activity,它的代码如下所示:

private TextView mTv;@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_animation2);    mTv = findViewById(R.id.tv);}public void onClick(View view) {    ObjectAnimator.ofFloat(mTv,"translationY",0,300).setDuration(1000).start();}public void onClick2(View view) {    Toast.makeText(this, "点击了“可挪动的属性view”",   Toast.LENGTH_SHORT).show();}

(3) 在 layout 文件夹下新建一个 activity_animation2.xml 文件,代码如下所示:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="demo1.xe.com.myapplication2.AnimationActivity">     <Button android:layout_width="match_parent"         android:text="点击该按钮可属性动画挪动view"         android:onClick="onClick"         android:layout_height="wrap_content" />     <TextView android:id="@+id/tv"         android:layout_width="300px"         android:gravity="center"         android:text="可挪动的属性view"         android:background="#FF0000"         android:onClick="onClick2"         android:layout_height="wrap_content" /></LinearLayout>

没点击 “点击该按钮可属性动画挪动view” 之前,它的运行效果图如下所示:

点击 “点击该按钮可属性动画挪动view” 这个按钮之后,它运行时挪动的过程中,某一瞬间的效果图如下所示:

对以上应用动画的例子进行总结得出:(1) 传统的 View 动画只是对影像做挪动,并不是真正的扭转 View 的地位,它的 fillAfter 属性默认值为 false,也就等同于做完动画之后会回到原地位;当 fillAfter 属性设置为 true 的时候,View 做完动画后,影像不会回到原始的地位,但如果在该 View 做一个事件监听,点击做完动画后的 View 是不会响应事件的,点击 View 的原始地位就会响应事件,因为在零碎眼里 View 做完动画之后它的地位没有产生扭转。(2) 属性动画在 Android 3.0版本以下的手机不能够用,要想应用,必须增加 nineoldandroids 这个依赖酷;属性动画不是对影像做挪动,而是真正的扭转了 View 的地位,如果在该 View 做一个事件监听,点击 View 的原始地位是不会有事件响应的,而点击做完动画之后的地位就会有事件响应。

3、扭转布局参数

通过扭转布局参数来实现 View 的滑动的思路有2个:(1) 向右挪动一个View,只须要把它的 marginLeft 参数增大,向其它方向挪动同理,只需扭转相应的 margin 参数;(2) 要挪动的 View 的旁边事后放一个 View,它的初始化宽度为0,而后要想右挪动View,只需把事后搁置的那个View的宽度增大,这样就把要挪动的 View “推”到左边了。示例如下所示:

(1) 新建一个布局文件,名字叫 activity_change_layout_parameter.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="demo1.xe.com.myapplication2.ChangeLayoutParameterActivity">     <Button android:layout_width="match_parent"         android:text="点击我可挪动第一个View"         android:onClick="onClick"         android:layout_height="wrap_content" />     <Button android:layout_width="match_parent"         android:text="点击我可挪动第二个View"         android:onClick="onClick2"         android:layout_height="wrap_content" />     <TextView android:id="@+id/tv"         android:layout_width="350px"         android:onClick="onClick3"         android:text="扭转布局参数可挪动的View"         android:layout_height="wrap_content" />     <LinearLayout android:layout_width="match_parent"         android:layout_height="wrap_content"         android:orientation="horizontal">         <View android:id="@+id/view"             android:layout_width="0px"             android:layout_height="1px"/>         <TextView android:id="@+id/tv2"             android:layout_width="350px"             android:onClick="onClick4"             android:text="扭转布局参数可挪动的View"             android:layout_height="wrap_content" />     </LinearLayout> </LinearLayout>

新建一个 Java 文件,名字叫 ChangeLayoutParameterActivity,它的代码如下所示:

TextView mTv;View mView;@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_change_layout_parameter);    mTv = findViewById(R.id.tv);    mView = findViewById(R.id.view);}public void onClick(View view) {    ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mTv.getLayoutParams();    params.leftMargin += 200;    params.width += 200;    mTv.requestLayout();}public void onClick2(View view) {    ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mView.getLayoutParams();    params.width += 200;    mView.requestLayout();}public void onClick3(View view) {    Toast.makeText(this,"点击了“扭转布局参数可挪动的第一个View” ",Toast.LENGTH_SHORT).show();}public void onClick4(View view) {    Toast.makeText(this,"点击了“扭转布局参数可挪动的第二个View” ",Toast.LENGTH_SHORT).show();}

没点击 “点击我可挪动第一个View” 按钮之前,效果图如下所示:

点击 “点击我可挪动第一个View” 按钮之后,效果图如下所示:

对以上扭转布局参数挪动 View 进行总结:不论是对 View 的 marginLeft 参数进行增大;还是要挪动的 View 的旁边事后放一个 View,而后要向右挪动View;他们两种办法都实现了 View 真正地位的挪动,而不是 View 影像的挪动;如果在 挪动的 View 做事件监听,点击原始地位不会事件响应,点击挪动后的地位会有事件响应。

4、应用 layout

应用 layout 挪动 View 的思路是这样的:在View的onTouchEvent办法中对MotionEvent中的坐标进行记录,记录按下的时候记录,在挪动的时候计算他们的偏移量,调用layout()对view的地位进行重绘制;上面举个例子:

(1) 新建一个布局文件,名叫 activity_use_layout.xml :

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="demo1.xe.com.myapplication2.UseLayoutActivity">     <TextView android:id="@+id/tv"         android:layout_width="wrap_content"         android:text="应用 Layout挪动View"         android:onClick="onClick"         android:layout_height="wrap_content" /></RelativeLayout>

(2) 新建一个 Java 文件,名叫 UseLayoutActivity,它的实现代码如下所示:

TextView mTv;private int lastX,lastY;@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_use_layout);    mTv = findViewById(R.id.tv);}@Overridepublic boolean onTouchEvent(MotionEvent event) {    int x = (int) event.getRawX();    int y = (int) event.getRawY();    switch (event.getAction()){        case MotionEvent.ACTION_DOWN:            lastX = x;            lastY = y;            break;          case MotionEvent.ACTION_MOVE:            int offsetX = x - lastX;            int offsetY = y - lastY;            mTv.layout(mTv.getLeft()+offsetX,            mTv.getTop()+offsetY,            mTv.getRight()+offsetX,            mTv.getBottom()+offsetY);            lastX = x;            lastY = y;            break;     }    return true;}public void onClick(View v){    Toast.makeText(this," 点击了 “应用 Layout挪动View” 按钮 ",Toast.LENGTH_SHORT).show();}

没滑动屏幕之前的效果图如下所示:

滑动屏幕某一瞬间的效果图如下所示:

对以上应用 layout 挪动 View 进行总结:应用 layout 挪动 View,扭转的不是 View 的影像,而是 View 真正的地位,所以如果要设置 View 的事件监听,点击挪动后的 View 才会响应事件;应用 layout 挪动 View 是和 Activity 的触摸事件联合应用的,触摸的时候获取绝对于屏幕触摸的x 和 y 坐标,而后手指挪动的过程中计算出挪动的间隔再加上 View 绝对于父视图的地位,失去 View 挪动后的地位,最初 View 应用 layout 办法 从新布局再进行从新绘画。

好了,本篇文章写到这里就完结了,因为自己技术水平无限,难免会有出错的中央,欢送批评指正,谢谢大家的浏览,另外附上Android的View滑动demo

关注微信公众号,浏览更多乏味的技术文章