乐趣区

关于java:Android中View的滑动

在生活中咱们应用 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;
   }
 }
@Override
protected 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();
           }
        }
      }
  }
@Override
protected 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;
@Override
protected 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;
@Override
protected 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;
@Override
protected 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;
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_use_layout);
    mTv = findViewById(R.id.tv);
}
@Override
public 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

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

退出移动版