用ViewDraghelper实现侧滑面板
2015-09-22 15:12
555 查看
首先自定义一个DragLayout继承FrameLayout,重写三个构造方法,并用this进行层级调用。
1. 创建ViewDragHelper辅助类
1.getViewHorizontalDragRange
此方法用于限制子view的横向拖拽范围。在复写其之前,可以先复写DragLayout的onSizeChanged方法,获取屏幕的宽和高,然后根据高度值求出mRange。mRange就是子view的横向拖拽范围。
此方法适用于处理当子view位置发生改变时要做的操作,如:将侧滑面板的位移值转交给主面板,侧滑面板开关时的伴随动画,状态的更新以及监听回调。
这里我将上面所列项目都实现了,下面是附上的代码,最后会附上完整代码。
在此之前,复写DragLayout的onFinishInflate方法,获得所有子view的引用。
位移值转交
伴随动画
此方法用于处理子view释放时要做的操作:如结束动画
public DragLayout(Context context) { this(context,null); } public DragLayout(Context context, AttributeSet attrs) { this(context, attrs,0); } public DragLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle);然后分三个步骤:实现DragLayout的子view的拖拽
1. 创建ViewDragHelper辅助类
public DragLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // 1.创建ViewDragHelper辅助类 mHelper = ViewDragHelper.create(this, 1.0f, callback); }2.转交触摸事件
// 2.转交触摸事件 public boolean onInterceptTouchEvent(android.view.MotionEvent ev) { return mHelper.shouldInterceptTouchEvent(ev); }; public boolean onTouchEvent(android.view.MotionEvent event) { try { mHelper.processTouchEvent(event); } catch (Exception e) { } return true; };3.复写回调callback
// 3.复写回调方法 Callback callback = new Callback() { // a.返回true 表示所有面板均可拖拽 返回false 表示所有面板均不可拖拽 @Override public boolean tryCaptureView(View child, int pointerId) { return true; } }再重写callback的另一个方法,clampViewPositionHorizontal,即可实现子view的拖拽。
// 返回值表示水平方向的拖拽位移 @Override public int clampViewPositionHorizontal(View child, int left, int dx) { left = fixLeft(left); return left; }下面是callback中可能用到的另外几个方法的介绍:
1.getViewHorizontalDragRange
此方法用于限制子view的横向拖拽范围。在复写其之前,可以先复写DragLayout的onSizeChanged方法,获取屏幕的宽和高,然后根据高度值求出mRange。mRange就是子view的横向拖拽范围。
// 获得容器的宽高,计算主面板的最大拖拽范围 @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { mHeight = getMeasuredHeight(); mWidth = getMeasuredWidth(); mRange = (int)(mWidth * 0.6f); }
// 限制主面板的拖拽范围 @Override public int getViewHorizontalDragRange(View child) { return mRange; }2.onViewPositionChanged
此方法适用于处理当子view位置发生改变时要做的操作,如:将侧滑面板的位移值转交给主面板,侧滑面板开关时的伴随动画,状态的更新以及监听回调。
这里我将上面所列项目都实现了,下面是附上的代码,最后会附上完整代码。
在此之前,复写DragLayout的onFinishInflate方法,获得所有子view的引用。
// 获得容器中的子view protected void onFinishInflate() { mLeft = (LinearLayout) getChildAt(0); mMain = (LinearLayout) getChildAt(1); };
位移值转交
// 将左面板的位移转交给主面板 if(changedView == mLeft) { mLeft.layout(0, 0, mWidth, mHeight); int newLeft = mMain.getLeft() + dx; newLeft = fixLeft(newLeft); mMain.layout(newLeft,0,newLeft+mWidth,mHeight); }
private int fixLeft(int left) { if(left < 0) { left = 0; }else if(left > mRange) { left = mRange; } return left; }
伴随动画
float percent = mMain.getLeft() * 1.0f / mRange; // 1. 左面板:缩放动画,平移动画,透明度变化 ViewHelper.setScaleX(mLeft, evaluate(percent, 0.5f, 1.0f)); ViewHelper.setScaleY(mLeft, evaluate(percent, 0.5f, 1.0f)); ViewHelper.setTranslationX(mLeft, evaluate(percent, -mWidth/2, 0)); ViewHelper.setAlpha(mLeft, evaluate(percent, 0.5f, 1.0f)); // 2. 主面板:缩放动画 ViewHelper.setScaleX(mMain, evaluate(percent, 1.0f, 0.8f)); ViewHelper.setScaleY(mMain, evaluate(percent, 1.0f, 0.8f));状态更新和监听回调
public interface OnDragUpdateListener{ void onOpen(); void onClose(); void onDragging(float percent); } private OnDragUpdateListener onDragUpdateListener; public static enum Status{ Open,Close,Dragging; } private Status status = Status.Close; public Status getStatus() { return status; } public void setStatus(Status status) { this.status = status; } public OnDragUpdateListener getOnDragUpdateListener() { return onDragUpdateListener; } public void setOnDragUpdateListener(OnDragUpdateListener onDragUpdateListener) { this.onDragUpdateListener = onDragUpdateListener; }
if(onDragUpdateListener != null) { onDragUpdateListener.onDragging(percent); } Status lastStatus = status; if(percent == 0) { status = Status.Close; }else if(percent == 1) { status = Status.Open; }else { status = Status.Dragging; } if(status != lastStatus) { if(status == Status.Close) { onDragUpdateListener.onClose(); }else if(status == Status.Open) { onDragUpdateListener.onOpen(); } }3.onViewReleased
此方法用于处理子view释放时要做的操作:如结束动画
// 当子view释放时要做的事,如:结束动画 @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { if(xvel == 0 && mMain.getLeft() > mRange * 0.5f) { open(); }else if(xvel > 0) { open(); }else { close(); } }
// 关闭侧滑面板的操作 protected void close() { close(true); } public void close(boolean isSmooth) { int finalLeft = 0; if(isSmooth) { // 1.触发平滑动画 if(mHelper.smoothSlideViewTo(mMain, finalLeft, 0)) { ViewCompat.postInvalidateOnAnimation(this); } }else { mMain.layout(finalLeft, 0, finalLeft+mWidth, mHeight); } } // 打开侧滑面板的操作 protected void open() { open(true); } public void open(boolean isSmooth) { int finalLeft = mRange; if(isSmooth) { // 1.触发平滑动画 if(mHelper.smoothSlideViewTo(mMain, finalLeft, 0)) { ViewCompat.postInvalidateOnAnimation(this); } }else { mMain.layout(finalLeft, 0, finalLeft+mWidth, mHeight); } } // 2.维持平滑动画 @Override public void computeScroll() { if(mHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } }下面是使用DragLayout,首先是activity_main.xml文件
<com.demo.viewdraghelperdemo.DragLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/dl" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/bg" > <LinearLayout android:id="@+id/ll_left" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="50dp" android:paddingLeft="10dp" android:paddingRight="50dp" android:paddingTop="50dp" > <ImageView android:layout_width="50dp" android:layout_height="50dp" android:layout_gravity="center_vertical" android:src="@drawable/header" /> <ListView android:id="@+id/lv_left" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> </LinearLayout> <com.demo.viewdraghelperdemo.MyLinearLayout android:id="@+id/ll_main" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff" android:orientation="vertical" > <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp" android:background="#9DD4FB" > <ImageView android:id="@+id/iv_header" android:layout_width="30dp" android:layout_height="30dp" android:layout_centerVertical="true" android:layout_marginLeft="15dp" android:src="@drawable/header" /> </RelativeLayout> <ListView android:id="@+id/lv_main" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" > </ListView> </com.demo.viewdraghelperdemo.MyLinearLayout> </com.demo.viewdraghelperdemo.DragLayout>MainActivity.java
package com.demo.viewdraghelperdemo; import java.util.Random; import android.animation.ObjectAnimator; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.animation.CycleInterpolator; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import com.demo.viewdraghelperdemo.DragLayout.OnDragUpdateListener; import com.nineoldandroids.view.ViewHelper; public class MainActivity extends Activity { private ImageView header; private DragLayout dl; private MyLinearLayout ll_main; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final ListView lv_left = (ListView) findViewById(R.id.lv_left); lv_left.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, Strings.list1){ @Override public View getView(int position, View convertView, ViewGroup parent) { TextView v = (TextView) super.getView(position, convertView, parent); v.setTextColor(Color.WHITE); return v; } }); ListView lv_main = (ListView) findViewById(R.id.lv_main); lv_main.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, Strings.list2){ @Override public View getView(int position, View convertView, ViewGroup parent) { TextView v = (TextView) super.getView(position, convertView, parent); v.setTextColor(Color.BLACK); return v; } }); dl = (DragLayout) findViewById(R.id.dl); header = (ImageView) findViewById(R.id.iv_header); header.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { dl.open(); } }); ll_main = (MyLinearLayout) findViewById(R.id.ll_main); ll_main.setDragLayout(dl); dl.setOnDragUpdateListener(new OnDragUpdateListener() { @Override public void onOpen() { Random r = new Random(); lv_left.smoothScrollToPosition(r.nextInt(20)); } @Override public void onDragging(float percent) { ViewHelper.setAlpha(header, (1 - percent) * 0.5f + 0.5f); } @Override public void onClose() { ObjectAnimator animator = ObjectAnimator.ofFloat(header, "translationX", 15); animator.setInterpolator(new CycleInterpolator(5)); animator.setDuration(500); animator.start(); } }); } }String.java,用于填充两个ListView的含有两个静态字符串数组的类
package com.demo.viewdraghelperdemo; public class Strings { public static String[] list1 = { "dugubaitian", "xuanxuan", "yueer", "chennan", "yuxin", "longwu", "dongfangfenghuang", "chuyu", "tantaixuan", "mengkeer", "xiaochen", "qingqing", "yefan", "jiziyue", "qinlan", "anmiaoyi", "shihao", "huolinger", "taiyinyutu" }; public static String[] list2 = { "shenmu", "busibumie", "changshengjie", "zhetian", "wanmeishijie", "gaoshoujimo", "xinyueyongheng", "wang", "qingyuxie", "zanmingming", "duxingaoshouzaidushi", "jixiemori", "chongfengxing", "youmingxiantu", "xijue", "dongni", "lanbenjiayi", "dadizhideng", "jipinmeinvdiguo", "xiaoyaofangdong", "wanmeirensheng","taoyunqingnian"}; }最后,为了屏蔽当侧滑面板打开时,主面板的滑动事件,自定义了一个LinearLayout,MyLinearLayout.java
package com.demo.viewdraghelperdemo; import com.demo.viewdraghelperdemo.DragLayout.Status; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.LinearLayout; public class MyLinearLayout extends LinearLayout { private DragLayout layout; public void setDragLayout(DragLayout layout) { this.layout = layout; } public MyLinearLayout(Context context) { super(context); } public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } public MyLinearLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if(layout.getStatus() == Status.Close) return super.onInterceptTouchEvent(ev); else { return true; } } @Override public boolean onTouchEvent(MotionEvent event) { if(layout.getStatus() == Status.Close) return super.onTouchEvent(event); else { try { layout.close(); } catch (Exception e) { e.printStackTrace(); } return true; } } }要运行这个工程可能要用到两个jar包,sdk\extras\android\support\v4\android-support-v4.jar和nineoldandroids.jar。
相关文章推荐
- Search a 2D Matrix
- Java总结篇系列:类型转换/造型
- 通过ValueAnimator 来实现按钮点击后倒计时的效果
- Jquery,seaJs异步刷新,克隆
- 疯狂讲解之GCD线程
- LeetCode 94: Binary Tree Inorder Traversal
- noip2008 笨小猴 (模拟)
- YARN内存使用优化配置
- 一道有意思的逻辑题
- 解决svn Authorization failed错误
- 找色
- C基础09天--指针+1
- 安装Oracle 11g R2静默安装安装
- 多线程锁的一点测试
- my.ini优化mysql数据库性能的十个参数(推荐)
- 各类文件头特征码
- Android手势密码
- 升级Xcode7+后遇到的问题
- 2015年9月21号css第一次课
- JavaScript继承方式详解