標籤:android 滑動 位置 事件 動態
跟手滑動
很多開發人員對布局的跟手滑動不太瞭解,在此就舉一個例子,看一個RelativeLayout的滑動顯示
原理
無論是跟手滑動,還是彈入彈齣動畫,本質上都是修改View或ViewGroup的位置,也即是setX() setY()這兩個方法。
跟手滑動是指,當使用者在螢幕上滑動時,某一塊布局,隨著手指的滑動而滑動。所以,它的實現原理就是在onTouch事件中動態獲得手指滑動的距離,然後修改view的位置。
跟手滑動時,有可能使用者只滑出來View的一部分就鬆手了,為了效果更好,我們按照使用者的滑動方向,將view以動畫的形式顯示出來。所以,它的原理就是使用ValueAnimator,動態修改view的位置
Codexml布局
我們的目的是讓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
Android:跟手滑動的布局ViewGroup