在生活中咱们应用 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.ge<span style="color:transparent">来源gaodai#ma#com搞*代#码网</span>tRawX(); 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
关注微信公众号,浏览更多乏味的技术文章