
前言
侧滑的实现方式有很多方式来实现,这次总结的VIEwDragHelper就是其中一种方式,VIEwDragHelper是2013年谷歌I/O大会发布的新的控件,为了解决界面控件拖拽问题。下面就是自己学习写的一个实现类似于QQ侧滑效果的实现。
activity_main.xml:
<com.yctc.drag.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" tools:context=".MainActivity" > <linearLayout 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:src="@drawable/head" /> <ListVIEw androID:ID="@+ID/lv_left" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" > </ListVIEw> </linearLayout> <com.yctc.drag.MylinearLayout androID:ID="@+ID/mll" 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="#18B6EF" androID:gravity="center_vertical" > <ImageVIEw androID:ID="@+ID/iv_header" androID:layout_wIDth="30dp" androID:layout_height="30dp" androID:layout_marginleft="15dp" androID:src="@drawable/head" /> <TextVIEw androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_centerHorizontal="true" androID:text="header" /> </relativeLayout> <ListVIEw androID:ID="@+ID/lv_main" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" > </ListVIEw> </com.yctc.drag.MylinearLayout></com.yctc.drag.DragLayout>
DragLayout.Java:
public class DragLayout extends FrameLayout { private static final String TAG = "TAG"; private VIEwDragHelper mDragHelper; private VIEwGroup mleftContent; private VIEwGroup mMainContent; private OnDragStatuschangelistener mListener; private Status mStatus = Status.Close; /** * 状态枚举 */ public static enum Status { Close,Open,Draging; } public interface OnDragStatuschangelistener{ voID onClose(); voID onopen(); voID onDraging(float percent); } public Status getStatus() { return mStatus; } public voID setStatus(Status mStatus) { this.mStatus = mStatus; } public voID setDragStatusListener(OnDragStatuschangelistener mListener){ this.mListener = mListener; } 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,defStyle); // a.初始化 (通过静态方法) mDragHelper = VIEwDragHelper.create(this,mCallback); } VIEwDragHelper.Callback mCallback = new VIEwDragHelper.Callback() { // c. 重写事件 // 1. 根据返回结果决定当前child是否可以拖拽 // child 当前被拖拽的VIEw // pointerID 区分多点触摸的ID @OverrIDe public boolean tryCaptureVIEw(VIEw child,int pointerID) { Log.d(TAG,"tryCaptureVIEw: " + child); return true; }; @OverrIDe public voID onVIEwCaptured(VIEw capturedChild,int activePointerID) { Log.d(TAG,"onVIEwCaptured: " + capturedChild); // 当capturedChild被捕获时,调用. super.onVIEwCaptured(capturedChild,activePointerID); } @OverrIDe public int getVIEwHorizontalDragRange(VIEw child) { // 返回拖拽的范围,不对拖拽进行真正的限制. 仅仅决定了动画执行速度 return mRange; } // 2. 根据建议值 修正将要移动到的(横向)位置 (重要) // 此时没有发生真正的移动 public int clampVIEwpositionHorizontal(VIEw child,int left,int dx) { // child: 当前拖拽的VIEw // left 新的位置的建议值,dx 位置变化量 // left = oldleft + dx; Log.d(TAG,"clampVIEwpositionHorizontal: " + "oldleft: " + child.getleft() + " dx: " + dx + " left: " +left); if(child == mMainContent){ left = fixleft(left); } return left; } // 3. 当VIEw位置改变的时候,处理要做的事情 (更新状态,伴随动画,重绘界面) // 此时,VIEw已经发生了位置的改变 @OverrIDe public voID onVIEwpositionChanged(VIEw changedVIEw,int top,int dx,int dy) { // changedVIEw 改变位置的VIEw // left 新的左边值 // dx 水平方向变化量 super.onVIEwpositionChanged(changedVIEw,left,top,dx,dy); Log.d(TAG,"onVIEwpositionChanged: " + "left: " + left + " dx: " + dx); int newleft = left; if(changedVIEw == mleftContent){ // 把当前变化量传递给mMainContent newleft = mMainContent.getleft() + dx; } // 进行修正 newleft = fixleft(newleft); if(changedVIEw == mleftContent) { // 当左面板移动之后,再强制放回去. mleftContent.layout(0,0 + mWIDth,0 + mHeight); mMainContent.layout(newleft,newleft + mWIDth,0 + mHeight); } // 更新状态,执行动画 dispatchDragEvent(newleft); // 为了兼容低版本,每次修改值之后,进行重绘 invalIDate(); } // 4. 当VIEw被释放的时候,处理的事情(执行动画) @OverrIDe public voID onVIEwReleased(VIEw releasedChild,float xvel,float yvel) { // VIEw releasedChild 被释放的子VIEw // float xvel 水平方向的速度,向右为+ // float yvel 竖直方向的速度,向下为+ Log.d(TAG,"onVIEwReleased: " + "xvel: " + xvel + " yvel: " + yvel); super.onVIEwReleased(releasedChild,xvel,yvel); // 判断执行 关闭/开启 // 先考虑所有开启的情况,剩下的就都是关闭的情况 if(xvel == 0 && mMainContent.getleft() > mRange / 2.0f){ open(); }else if (xvel > 0) { open(); }else { close(); } } @OverrIDe public voID onVIEwDragStateChanged(int state) { // Todo auto-generated method stub super.onVIEwDragStateChanged(state); } }; /** * 根据范围修正左边值 * @param left * @return */ private int fixleft(int left) { if(left < 0){ return 0; }else if (left > mRange) { return mRange; } return left; } protected voID dispatchDragEvent(int newleft) { float percent = newleft * 1.0f/ mRange; //0.0f -> 1.0f Log.d(TAG,"percent: " + percent); if(mListener != null){ mListener.onDraging(percent); } // 更新状态,执行回调 Status preStatus = mStatus; mStatus = updateStatus(percent); if(mStatus != preStatus){ // 状态发生变化 if(mStatus == Status.Close){ // 当前变为关闭状态 if(mListener != null){ mListener.onClose(); } }else if (mStatus == Status.Open) { if(mListener != null){ mListener.onopen(); } } }// * 伴随动画: animVIEws(percent); } private Status updateStatus(float percent) { if(percent == 0f){ return Status.Close; }else if (percent == 1.0f) { return Status.Open; } return Status.Draging; } private voID animVIEws(float percent) { // > 1. 左面板: 缩放动画,平移动画,透明度动画 // 缩放动画 0.0 -> 1.0 >>> 0.5f -> 1.0f >>> 0.5f * percent + 0.5f // mleftContent.setScaleX(0.5f + 0.5f * percent); // mleftContent.setScaleY(0.5f + 0.5f * percent); VIEwHelper.setScaleX(mleftContent,evaluate(percent,0.5f,1.0f)); VIEwHelper.setScaleY(mleftContent,0.5f + 0.5f * percent); // 平移动画: -mWIDth / 2.0f -> 0.0f VIEwHelper.setTranslationX(mleftContent,-mWIDth / 2.0f,0)); // 透明度: 0.5 -> 1.0f VIEwHelper.setAlpha(mleftContent,1.0f)); // > 2. 主面板: 缩放动画 // 1.0f -> 0.8f VIEwHelper.setScaleX(mMainContent,1.0f,0.8f)); VIEwHelper.setScaleY(mMainContent,0.8f)); // > 3. 背景动画: 亮度变化 (颜色变化) getBackground().setcolorFilter((Integer)evaluatecolor(percent,color.BLACK,color.@R_502_3318@),Mode.SRC_OVER); } /** * 估值器 * @param fraction * @param startValue * @param endValue * @return */ public float evaluate(float fraction,Number startValue,Number endValue) { float startfloat = startValue.floatValue(); return startfloat + fraction * (endValue.floatValue() - startfloat); } /** * 颜色变化过度 * @param fraction * @param startValue * @param endValue * @return */ public Object evaluatecolor(float fraction,Object startValue,Object endValue) { int startInt = (Integer) startValue; int startA = (startInt >> 24) & 0xff; int startR = (startInt >> 16) & 0xff; int startG = (startInt >> 8) & 0xff; int startB = startInt & 0xff; int endInt = (Integer) endValue; int endA = (endInt >> 24) & 0xff; int endR = (endInt >> 16) & 0xff; int endG = (endInt >> 8) & 0xff; int endB = endInt & 0xff; return (int)((startA + (int)(fraction * (endA - startA))) << 24) | (int)((startR + (int)(fraction * (endR - startR))) << 16) | (int)((startG + (int)(fraction * (endG - startG))) << 8) | (int)((startB + (int)(fraction * (endB - startB)))); } @OverrIDe public voID computeScroll() { super.computeScroll(); // 2. 持续平滑动画 (高频率调用) if(mDragHelper.continueSettling(true)){ // 如果返回true,动画还需要继续执行 VIEwCompat.postInvalIDateOnAnimation(this); } } public voID close(){ close(true); } /** * 关闭 */ public voID close(boolean isSmooth) { int finalleft = 0; if(isSmooth){ // 1. 触发一个平滑动画 if(mDragHelper.smoothSlIDeVIEwTo(mMainContent,finalleft,0)){ // 返回true代表还没有移动到指定位置,需要刷新界面. // 参数传this(child所在的VIEwGroup) VIEwCompat.postInvalIDateOnAnimation(this); } }else { mMainContent.layout(finalleft,finalleft + mWIDth,0 + mHeight); } } public voID open(){ open(true); } /** * 开启 */ public voID open(boolean isSmooth) { int finalleft = mRange; if(isSmooth){ // 1. 触发一个平滑动画 if(mDragHelper.smoothSlIDeVIEwTo(mMainContent,0 + mHeight); } } private int mHeight; private int mWIDth; private int mRange; // b.传递触摸事件 @OverrIDe public boolean onIntercepttouchEvent(MotionEvent ev) { // 传递给mDragHelper return mDragHelper.shouldIntercepttouchEvent(ev); } @OverrIDe public boolean ontouchEvent(MotionEvent event) { try { mDragHelper.processtouchEvent(event); } catch (Exception e) { e.printstacktrace(); } // 返回true,持续接受事件 return true; } @OverrIDe protected voID onFinishInflate() { super.onFinishInflate(); // Github // 写注释 // 容错性检查 (至少有俩子VIEw,子VIEw必须是VIEwGroup的子类) if(getChildCount() < 2){ throw new IllegalStateException("布局至少有俩孩子. Your VIEwGroup must have 2 children at least."); } if(!(getChildAt(0) instanceof VIEwGroup && getChildAt(1) instanceof VIEwGroup)){ throw new IllegalArgumentException("子VIEw必须是VIEwGroup的子类. Your children must be an instance of VIEwGroup"); } mleftContent = (VIEwGroup) getChildAt(0); mMainContent = (VIEwGroup) getChildAt(1); } @OverrIDe protected voID onSizeChanged(int w,int h,int olDW,int oldh) { super.onSizeChanged(w,h,olDW,oldh); // 当尺寸有变化的时候调用 mHeight = getMeasuredHeight(); mWIDth = getMeasureDWIDth(); // 移动的范围 mRange = (int) (mWIDth * 0.6f); }}MylineatLayout.java:
public class MylinearLayout extends linearLayout { private DragLayout mDragLayout; public MylinearLayout(Context context) { super(context); } public MylinearLayout(Context context,AttributeSet attrs) { super(context,attrs); } public voID setDraglayout(DragLayout mDragLayout){ this.mDragLayout = mDragLayout; } @OverrIDe public boolean onIntercepttouchEvent(MotionEvent ev) { // 如果当前是关闭状态,按之前方法判断 if(mDragLayout.getStatus() == Status.Close){ return super.onIntercepttouchEvent(ev); }else { return true; } } @OverrIDe public boolean ontouchEvent(MotionEvent event) { // 如果当前是关闭状态,按之前方法处理 if(mDragLayout.getStatus() == Status.Close){ return super.ontouchEvent(event); }else { // 手指抬起,执行关闭 *** 作 if(event.getAction() == MotionEvent.ACTION_UP){ mDragLayout.close(); } return true; } }}MainActivity.java:
public class MainActivity extends Activity { private static final String TAG = "TAG"; @OverrIDe protected voID onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestwindowFeature(Window.FEATURE_NO_Title); setContentVIEw(R.layout.activity_main); final ListVIEw mleftList = (ListVIEw) findVIEwByID(R.ID.lv_left); final ListVIEw mMainList = (ListVIEw) findVIEwByID(R.ID.lv_main); final ImageVIEw mheaderImage = (ImageVIEw) findVIEwByID(R.ID.iv_header); MylinearLayout mlinearLayout = (MylinearLayout) findVIEwByID(R.ID.mll); // 查找Draglayout,设置监听 DragLayout mDragLayout = (DragLayout) findVIEwByID(R.ID.dl); // 设置引用 mlinearLayout.setDraglayout(mDragLayout); mDragLayout.setDragStatusListener(new OnDragStatuschangelistener() { @OverrIDe public voID onopen() { Utils.showToast(MainActivity.this,"onopen"); // 左面板ListVIEw随机设置一个条目 Random random = new Random(); int nextInt = random.nextInt(50); mleftList.smoothScrollToposition(nextInt); } @OverrIDe public voID onDraging(float percent) { Log.d(TAG,"onDraging: " + percent);// 0 -> 1 // 更新图标的透明度 // 1.0 -> 0.0 VIEwHelper.setAlpha(mheaderImage,1 - percent); } @OverrIDe public voID onClose() { Utils.showToast(MainActivity.this,"onClose"); // 让图标晃动// mheaderImage.setTranslationX(translationX) ObjectAnimator mAnim = ObjectAnimator.offloat(mheaderImage,"translationX",15.0f); mAnim.setInterpolator(new CycleInterpolator(4)); mAnim.setDuration(500); mAnim.start(); } }); mleftList.setAdapter(new ArrayAdapter<String>(this,androID.R.layout.simple_List_item_1,Cheeses.sCheeseStrings){ @OverrIDe public VIEw getVIEw(int position,VIEw convertVIEw,VIEwGroup parent) { VIEw vIEw = super.getVIEw(position,convertVIEw,parent); TextVIEw mText = ((TextVIEw)vIEw); mText.setTextcolor(color.WHITE); return vIEw; } }); mMainList.setAdapter(new ArrayAdapter<String>(this,Cheeses.nameS)) }}以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
总结以上是内存溢出为你收集整理的ViewDragHelper实现QQ侧滑效果全部内容,希望文章能够帮你解决ViewDragHelper实现QQ侧滑效果所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)