跟手滑动
很多开发者对布局的跟手滑动不太了解,在此就举一个例子,看一个RelativeLayout的滑动显示
原理
无论是跟手滑动,还是弹入弹出动画,本质上都是修改View或ViewGroup的位置,也即是setX() setY()这两个方法。
跟手滑动
跟手滑动是指,当用户在屏幕上滑动时,某一块布局,随着手指的滑动而滑动。所以,它的实现原理就是在onTouch事件中动态获得手指滑动的距离,然后修改view的位置。
弹入弹出动画
跟手滑动时,有可能用户只滑出来View的一部分就松手了,为了效果更好,我们按照用户的滑动方向,将view以动画的形式显示出来。所以,它的原理就是使用ValueAnimator,动态修改view的位置
Code
xml布局
我们的目的是让id为rl_left的RelativeLayout,从屏幕左边随手滑出,也可以隐藏到屏幕左侧。
<RelativeLayout 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" android:background="@android:color/white" > <Button android:id="@+id/btn_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:text="show" /> <Button android:id="@+id/btn_2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_below="@id/btn_1" android:text="hide" /> <TextView android:id="@+id/tv_show" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> <RelativeLayout android:id="@+id/rl_left" android:layout_width="@dimen/rl_left_w" android:layout_height="match_parent" android:background="#00ff00" > <ListView android:id="@+id/lv_test" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout> </RelativeLayout>
MianActivity-滑动及动画的控制
重点关注的方法:
slideToShow
slideToHide
onTouch
package com.example.net.mobctrl.ottotest; import java.util.ArrayList; import java.util.List; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.app.Activity; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.animation.DecelerateInterpolator; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; /** * * @author Zheng Haibo * */ public class MainActivity extends Activity { private RelativeLayout rl_left; private ListView listView; private TextView tvShow; private int rlWidth;// 布局的宽度 private static final int MAX_OFFSET = 5;// 5个像素误差,滑动小于5个像素就没有动画 private float downX;// 按下时的点 private float viewXdown;// 按下时View的位置 private boolean lastSlidePull = false;// 最后一次滑动的方向 private float maxOffset = 0;// 最大的滑动距离 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); System.out.println("debug:onCreate"); setContentView(R.layout.activity_main); findViewById(R.id.btn_1).setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { slideToShow(); } }); findViewById(R.id.btn_2).setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { slideToHide(); } }); tvShow = (TextView) findViewById(R.id.tv_show); initLeftView(); } private void initLeftView() { rl_left = (RelativeLayout) findViewById(R.id.rl_left); rlWidth = getResources().getDimensionPixelSize(R.dimen.rl_left_w); rl_left.setX(-rlWidth);// 将rl_left的位置移动到手机屏幕左外 // 初始化RelativeLayout的View,此处以ListView举例 listView = (ListView) rl_left.findViewById(R.id.lv_test); listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, getItemData())); listView.setOnItemClickListener(itemListener); } /** * 填充假数据 * * @return */ private List<String> getItemData() { List<String> list = new ArrayList<String>(); for (int i = 0; i < 16; i++) { list.add("item" + i); } return list; } private OnItemClickListener itemListener = new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { slideToHide(); tvShow.setText(String.format("you click item %s!", arg2)); } }; /** * 使用ValueAnimator将rl_left以动画的形式弹入到界面 */ private void slideToShow() { float startX = rl_left.getX(); ValueAnimator valueAnimator = ValueAnimator.ofInt((int) startX, 0); valueAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int offset = (Integer) animation.getAnimatedValue(); rl_left.setX(offset); } }); valueAnimator.setInterpolator(new DecelerateInterpolator()); float fraction = Math.abs(startX / rlWidth); valueAnimator.setDuration((long) (600 * fraction)); valueAnimator.start(); } /** * 使用ValueAnimator将rl_left以动画的形式弹出去 */ private void slideToHide() { float startX = rl_left.getX(); ValueAnimator valueAnimator = ValueAnimator.ofInt((int) startX, -rlWidth); valueAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int offset = (Integer) animation.getAnimatedValue(); rl_left.setX(offset); } }); valueAnimator.setInterpolator(new DecelerateInterpolator()); float fraction = Math.abs((rlWidth + startX) / rlWidth); valueAnimator.setDuration((long) (400 * fraction)); valueAnimator.start(); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: this.downX = x; this.viewXdown = rl_left.getX(); break; case MotionEvent.ACTION_MOVE: float offset = (event.getX() - downX);// 滑动距离 float posX = viewXdown + offset;// 计算可能的位置 maxOffset = maxOffset > Math.abs(offset) ? maxOffset : Math .abs(offset); if (offset > 0) {// pull to show rl_left.setX(posX < 0 ? posX : 0); if (posX >= 0) {// 防止不跟手,更新downX的值 this.downX += posX; } lastSlidePull = true; } else {// push to hide rl_left.setX(posX > -rlWidth ? posX : -rlWidth); if (posX <= -rlWidth) {// 防止不跟手,更新downX的值 this.downX += (posX + rlWidth); } lastSlidePull = false; } break; case MotionEvent.ACTION_UP: if (maxOffset < MAX_OFFSET) {// 防止抖动 return super.onTouchEvent(event); } // 使用动画滑动到指定位置 if (lastSlidePull) { slideToShow(); } else { slideToHide(); } break; default: break; } return super.onTouchEvent(event); } @Override protected void onDestroy() { super.onDestroy(); } }
效果
原谅我,做截Gif太麻烦了。。
更多交流
Android开发联盟QQ群:272209595