转载请标明出处:

http://blog.csdn.net/developer_jiangqq/article/details/50253925

本文出自:【江清清的博客】

(一).前言:

【好消息】个人站点已经上线执行,后面博客以及技术干货等精彩文章会同步更新。请大家关注收藏:http://www.lcode.org

这两天QQ进行了重大更新(6.X)尤其在UI风格上面由之前的蓝色换成了白色居多了,側滑效果也发生了一些变化,那我们今天来模仿实现一个QQ6.X版本号的側滑界面效果。

今天我们还是採用神器ViewDragHelper来实现。之前我们曾经基于ViewDragHelper的使用和打造QQ5.X效果了。基本用法能够点击以下的连接:

假设对于ViewDragHelper不是特别了解的朋友能够查看上面的文章学习一下。

本次实例详细代码已经上传到以下的项目中。欢迎各位去star和fork一下。

https://github.com/jiangqqlmj/DragHelper4QQ

FastDev4Android框架项目地址:https://github.com/jiangqqlmj/FastDev4Android

(二).ViewGragHelper的基本使用

前面我们学习ViewGragHelper的基本用法。同一时候也知道了里边的若干个方法的用途。以下我们还是把主要的使用步骤温习一下。要使用ViewGragHelper实现子View拖拽移动的过程例如以下:

  1. 创建ViewGragHelper实例(传入Callback)
  2. 重写事件拦截处理方法onInterceptTouch和onTouchEvent
  3. 实现Callback,实现当中的相关方法tryCaptureView以及水平或者垂直方向移动的距离方法

更加详细分析大家能够看前一篇博客,或者我们今天这边会通过详细实例解说一下。

(三).QQ5.X側滑效果实现分析:

在正式版本号QQ中的側滑效果例如以下:

观察上面我们能够理解为两个View,一个是底部的相当于左側功能View,另外一个是上层主功能内容View,我们在上面进行拖拽上层View或者左右滑动的时候。上层和下层的View对应进行滑动以及View大小变化,同一时候增加相关的动画。当然我们点击上层的View能够进行打开或者关闭側滑菜单。

(四).側滑效果自己定义组件实现

1.首先我们这边集成自FrameLayout创建一个自己定义View  DragLayout。

内部的定义的一些变量例如以下(主要包含一些配置类。手势,ViewDragHelper实例。屏幕宽高,拖拽的子视图View等)

  1. //是否带有阴影效果
  2. private boolean isShowShadow = true;
  3. //手势处理类
  4. private GestureDetectorCompat gestureDetector;
  5. //视图拖拽移动帮助类
  6. private ViewDragHelper dragHelper;
  7. //滑动监听器
  8. private DragListener dragListener;
  9. //水平拖拽的距离
  10. private int range;
  11. //宽度
  12. private int width;
  13. //高度
  14. private int height;
  15. //main视图距离在ViewGroup距离左边的距离
  16. private int mainLeft;
  17. private Context context;
  18. private ImageView iv_shadow;
  19. //左側布局
  20. private RelativeLayout vg_left;
  21. //右側(主界面布局)
  22. private CustomRelativeLayout vg_main;

然后在内部还定义了一个回调接口主要处理拖拽过程中的一些页面打开。关闭以及滑动中的事件回调:

  1. /**
  2. * 滑动相关回调接口
  3. */
  4. public interface DragListener {
  5. //界面打开
  6. public void onOpen();
  7. //界面关闭
  8. public void onClose();
  9. //界面滑动过程中
  10. public void onDrag(float percent);
  11. }

2.開始创建ViewDragHelper实例。依旧在自己定义View DragLayout初始化的时候创建。使用ViewGragHelper的静态方法:

  1. public DragLayout(Context context,AttributeSet attrs, int defStyle) {
  2. super(context, attrs, defStyle);
  3. gestureDetector = new GestureDetectorCompat(context, new YScrollDetector());
  4. dragHelper =ViewDragHelper.create(this, dragHelperCallback);
  5. }

当中create()方法创建的时候传入了一个dragHelperCallBack回调类,将会在第四点中讲到。

3.接着须要重写ViewGroup中事件方法,拦截触摸事件给ViewGragHelper内部进行处理,这样达到拖拽移动子View视图的目的;

  1. /**
  2. * 拦截触摸事件
  3. * @param ev
  4. * @return
  5. */
  6. @Override
  7. public boolean onInterceptTouchEvent(MotionEvent ev) {
  8. return dragHelper.shouldInterceptTouchEvent(ev) &&gestureDetector.onTouchEvent(ev);
  9. }
  10. /**
  11. * 将拦截的到事件给ViewDragHelper进行处理
  12. * @param e
  13. * @return
  14. */
  15. @Override
  16. public boolean onTouchEvent(MotionEvent e){
  17. try {
  18. dragHelper.processTouchEvent(e);
  19. } catch (Exception ex) {
  20. ex.printStackTrace();
  21. }
  22. return false;
  23. }

这边我们在onInterceptTouchEvent拦截让事件从父控件往子View中转移。然后在onTouchEvent方法中拦截让ViewDragHelper进行消费处理。

4.開始自己定义创建ViewDragHelper.Callback的实例dragHelperCallback分别实现一个抽象方法tryCaptureView以及重写以下若干个方法来实现側滑功能。以下一个个来看一下。

  1. /**
  2. * 拦截全部的子View
  3. * @param child Child the user is attempting to capture
  4. * @param pointerId ID of the pointer attempting the capture
  5. * @return
  6. */
  7. @Override
  8. public boolean tryCaptureView(Viewchild, int pointerId) {
  9. return true;
  10. }

该进行拦截ViewGroup(本例中为:DragLayout)中全部的子View,直接返回true,表示全部的子View都能够进行拖拽移动。

  1. /**
  2. * 水平方向移动
  3. * @param child Child view beingdragged
  4. * @param left Attempted motion alongthe X axis
  5. * @param dx Proposed change inposition for left
  6. * @return
  7. */
  8. @Override
  9. public int clampViewPositionHorizontal(View child, int left, int dx) {
  10. if (mainLeft + dx < 0) {
  11. return 0;
  12. } else if (mainLeft + dx >range) {
  13. return range;
  14. } else {
  15. return left;
  16. }
  17. }

实现该方法表示水平方向滑动,同一时候方法中会进行推断边界值,比如当上面的main view已经向左移动边界之外了。直接返回0,表示向左最左边仅仅能x=0。然后向右移动会推断向右最变得距离range。至于range的初始化后边会讲到。

除了这两种情况之外,就是直接返回left就可以。

  1. /**
  2. * 设置水平方向滑动的最远距离
  3. *@param child Child view to check 屏幕宽度
  4. * @return
  5. */
  6. @Override
  7. public int getViewHorizontalDragRange(View child) {
  8. return width;
  9. }

该方法有必要实现,由于该方法在Callback内部默认返回0,也就是说,假设的view的click事件为true,那么会出现整个子View没法拖拽移动的情况了。那么这边直接返回left view宽度了,表示水平方向滑动的最远距离了。

  1. /**
  2. * 当拖拽的子View。手势释放的时候回调的方法, 然后依据左滑或者右滑的距离进行推断打开或者关闭
  3. * @param releasedChild
  4. * @param xvel
  5. * @param yvel
  6. */
  7. @Override
  8. public void onViewReleased(View releasedChild, float xvel, float yvel) {
  9. super.onViewReleased(releasedChild,xvel, yvel);
  10. if (xvel > 0) {
  11. open();
  12. } else if (xvel < 0) {
  13. close();
  14. } else if (releasedChild == vg_main&& mainLeft > range * 0.3) {
  15. open();
  16. } else if (releasedChild == vg_left&& mainLeft > range * 0.7) {
  17. open();
  18. } else {
  19. close();
  20. }
  21. }

该方法在拖拽子View移动手指释放的时候被调用,这是会推断移动向左。向右的意图,进行打开或者关闭man view(上层视图)。以下是实现的最后一个方法:onViewPositionChanged

  1. /**
  2. * 子View被拖拽 移动的时候回调的方法
  3. * @param changedView View whoseposition changed
  4. * @param left New X coordinate of theleft edge of the view
  5. * @param top New Y coordinate of thetop edge of the view
  6. * @param dx Change in X position fromthe last call
  7. * @param dy Change in Y position fromthe last call
  8. */
  9. @Override
  10. public void onViewPositionChanged(View changedView, int left, int top,
  11. int dx, int dy) {
  12. if (changedView == vg_main) {
  13. mainLeft = left;
  14. } else {
  15. mainLeft = mainLeft + left;
  16. }
  17. if (mainLeft < 0) {
  18. mainLeft = 0;
  19. } else if (mainLeft > range) {
  20. mainLeft = range;
  21. }
  22.  
  23. if (isShowShadow) {
  24. iv_shadow.layout(mainLeft, 0,mainLeft + width, height);
  25. }
  26. if (changedView == vg_left) {
  27. vg_left.layout(0, 0, width,height);
  28. vg_main.layout(mainLeft, 0,mainLeft + width, height);
  29. }
  30. dispatchDragEvent(mainLeft);
  31. }
  32. };

该方法是在我们进行拖拽移动子View的过程中进行回调,依据移动坐标位置。然后进行又一次定义left view和main view。同一时候调用dispathDragEvent()方法进行拖拽事件相关处理分发同一时候依据状态来回调接口:

  1. /**
  2. * 进行处理拖拽事件
  3. * @param mainLeft
  4. */
  5. private void dispatchDragEvent(int mainLeft) {
  6. if (dragListener == null) {
  7. return;
  8. }
  9. float percent = mainLeft / (float)range;
  10. //依据滑动的距离的比例
  11. animateView(percent);
  12. //进行回调滑动的百分比
  13. dragListener.onDrag(percent);
  14. Status lastStatus = status;
  15. if (lastStatus != getStatus()&& status == Status.Close) {
  16. dragListener.onClose();
  17. } else if (lastStatus != getStatus()&& status == Status.Open) {
  18. dragListener.onOpen();
  19. }
  20. }

该方法中有一行代码float percent=mainLeft/(float)range;算到一个百分比后面会用到

5.至于子View布局的获取初始化以及宽高和水平滑动距离的大小设置方法:

  1. /**
  2. * 布局载入完毕回调
  3. * 做一些初始化的操作
  4. */
  5. @Override
  6. protected void onFinishInflate() {
  7. super.onFinishInflate();
  8. if (isShowShadow) {
  9. iv_shadow = new ImageView(context);
  10. iv_shadow.setImageResource(R.mipmap.shadow);
  11. LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
  12. addView(iv_shadow, 1, lp);
  13. }
  14. //左側界面
  15. vg_left = (RelativeLayout)getChildAt(0);
  16. //右側(主)界面
  17. vg_main = (CustomRelativeLayout)getChildAt(isShowShadow ? 2 : 1);
  18. vg_main.setDragLayout(this);
  19. vg_left.setClickable(true);
  20. vg_main.setClickable(true);
  21. }
  22. 以及控件大小发生变化回调的方法:
  23. @Override
  24. protected void onSizeChanged(int w, int h,int oldw, int oldh) {
  25. super.onSizeChanged(w, h, oldw, oldh);
  26. width = vg_left.getMeasuredWidth();
  27. height = vg_left.getMeasuredHeight();
  28. //能够水平拖拽滑动的距离 一共为屏幕宽度的80%
  29. range = (int) (width *0.8f);
  30. }

在该方法中我们能够实时获取宽和高以及拖拽水平距离。

6.上面的全部核心代码都为使用ViewDragHelper实现子控件View拖拽移动的方法,可是依据我们这边側滑效果还须要实现动画以及滑动过程中View的缩放效果。所以我们这边引入了一个动画开源库:

然后依据前面算出来的百分比来缩放View视图:

  1. /**
  2. * 依据滑动的距离的比例,进行平移动画
  3. * @param percent
  4. */
  5. private void animateView(float percent) {
  6. float f1 = 1 - percent * 0.5f;
  7.  
  8. ViewHelper.setTranslationX(vg_left,-vg_left.getWidth() / 2.5f + vg_left.getWidth() / 2.5f * percent);
  9. if (isShowShadow) {
  10. //阴影效果视图大小进行缩放
  11. ViewHelper.setScaleX(iv_shadow, f1* 1.2f * (1 - percent * 0.10f));
  12. ViewHelper.setScaleY(iv_shadow, f1* 1.85f * (1 - percent * 0.10f));
  13. }
  14. }

7.当然除了上面这些还缺少一个效果就是,当我们滑动过程中假如我们手指释放,依照常理来讲view就不会在进行移动了,那么这边我们须要一个加速度当我们释放之后。还能保持一定的速度。该怎么样实现呢?答案就是实现computeScroll()方法。

  1. /**
  2. * 有加速度,当我们停止滑动的时候,该不会马上停止动画效果
  3. */
  4. @Override
  5. public void computeScroll() {
  6. if (dragHelper.continueSettling(true)){
  7. ViewCompat.postInvalidateOnAnimation(this);
  8. }
  9. }

OK上面关于DragLayout的核心代码就差点儿相同这么多了,以下是使用DragLayout类来实现側滑效果啦。

(五).側滑效果组件使用

1.首先使用的布局文件例如以下:

  1. <com.chinaztt.widget.DragLayout
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:id="@+id/dl"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. android:background="@android:color/transparent"
  7. >
  8. <!--下层 左边的布局-->
  9. <includelayout="@layout/left_view_layout"/>
  10. <!--上层 右边的主布局-->
  11. <com.chinaztt.widget.CustomRelativeLayout
  12. android:layout_width="match_parent"
  13. android:layout_height="match_parent"
  14. android:background="#FFFFFF"
  15. >
  16. <LinearLayout
  17. android:layout_width="fill_parent"
  18. android:layout_height="fill_parent"
  19. android:orientation="vertical"
  20. >
  21. <RelativeLayout
  22. android:id="@+id/rl_title"
  23. android:layout_width="match_parent"
  24. android:layout_height="49dp"
  25. android:gravity="bottom"
  26. android:background="@android:color/holo_orange_light"
  27. >
  28. <includelayout="@layout/common_top_bar_layout"/>
  29. </RelativeLayout>
  30. <!--中间内容后面放入Fragment-->
  31. <FrameLayout
  32. android:layout_width="fill_parent"
  33. android:layout_height="fill_parent"
  34. >
  35. <fragment
  36. android:id="@+id/main_info_fragment"
  37. class="com.chinaztt.fragment.OneFragment"
  38. android:layout_width="fill_parent"
  39. android:layout_height="fill_parent"/>
  40. </FrameLayout>
  41. </LinearLayout>
  42. </com.chinaztt.widget.CustomRelativeLayout>
  43. </com.chinaztt.widget.DragLayout>

该布局文件里父层View就是DragLayout,然后内部有两个RelativeLayout布局,分别充当下一层布局和上一层主布局。

2.以下我们来看一下下层菜单布局,这边我专门写了一个left_view_layout.xml文件,当中主要分为三块,第一块顶部为头像个人基本信息布局,中间为功能入口列表,底部是设置等功能,详细布局代码例如以下:

  1. <RelativeLayout
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. android:paddingTop="70dp"
  7. android:background="@drawable/sidebar_bg"
  8. >
  9. <LinearLayout
  10. android:id="@+id/ll1"
  11. android:paddingLeft="30dp"
  12. android:layout_width="fill_parent"
  13. android:layout_height="wrap_content"
  14. android:orientation="vertical">
  15. <!--头像,昵称信息-->
  16. <LinearLayout
  17. android:layout_width="match_parent"
  18. android:layout_height="70dp"
  19. android:orientation="horizontal"
  20. android:gravity="center_vertical"
  21. >
  22. <com.chinaztt.widget.RoundAngleImageView
  23. android:id="@+id/iv_bottom"
  24. android:layout_width="50dp"
  25. android:layout_height="50dp"
  26. android:scaleType="fitXY"
  27. android:src="@drawable/icon_logo"
  28. app:roundWidth="25dp"
  29. app:roundHeight="25dp"/>
  30. <LinearLayout
  31. android:layout_width="fill_parent"
  32. android:layout_height="wrap_content"
  33. android:gravity="center_vertical"
  34. android:layout_gravity="center_vertical"
  35. android:orientation="vertical">
  36. <RelativeLayout
  37. android:layout_width="fill_parent"
  38. android:layout_height="wrap_content"
  39. >
  40. <TextView
  41. android:layout_width="wrap_content"
  42. android:layout_height="wrap_content"
  43. android:layout_centerVertical="true"
  44. android:layout_marginLeft="15dp"
  45. android:text="名字:jiangqqlmj"
  46. android:textColor="@android:color/black"
  47. android:textSize="15sp" />
  48. <ImageButton
  49. android:layout_alignParentRight="true"
  50. android:layout_centerVertical="true"
  51. android:layout_marginRight="100dp"
  52. android:layout_width="22dp"
  53. android:layout_height="22dp"
  54. android:background="@drawable/qrcode_selector"/>
  55. </RelativeLayout>
  56.  
  57. <TextView
  58. android:layout_width="wrap_content"
  59. android:layout_height="wrap_content"
  60. android:layout_gravity="center_vertical"
  61. android:layout_marginLeft="15dp"
  62. android:text="QQ:781931404"
  63. android:textColor="@android:color/black"
  64. android:textSize="13sp" />
  65. </LinearLayout>
  66. </LinearLayout>
  67. <LinearLayout
  68. android:layout_width="fill_parent"
  69. android:layout_height="wrap_content"
  70. android:gravity="center_vertical"
  71. android:orientation="horizontal">
  72. <ImageView
  73. android:layout_width="17dp"
  74. android:layout_height="17dp"
  75. android:scaleType="fitXY"
  76. android:src="@drawable/sidebar_signature_nor"/>
  77. <TextView
  78. android:layout_marginLeft="5dp"
  79. android:textSize="13sp"
  80. android:textColor="#676767"
  81. android:layout_width="fill_parent"
  82. android:layout_height="wrap_content"
  83. android:text="用心做产品!"/>
  84. </LinearLayout>
  85. </LinearLayout>
  86.  
  87. <!--底部功能条-->
  88. <includelayout="@layout/left_view_bottom_layout"
  89. android:id="@+id/bottom_view"
  90. />
  91. <!--中间列表-->
  92. <ListView
  93. android:id="@+id/lv"
  94. android:layout_width="match_parent"
  95. android:layout_height="wrap_content"
  96. android:layout_above="@id/bottom_view"
  97. android:layout_below="@id/ll1"
  98. android:layout_marginBottom="30dp"
  99. android:layout_marginTop="70dp"
  100. android:cacheColorHint="#00000000"
  101. android:listSelector="@drawable/lv_click_selector"
  102. android:divider="@null"
  103. android:scrollbars="none"
  104. android:textColor="#ffffff"/>
  105. </RelativeLayout>

该布局还是比較简单的,对于上层主内容布局这边就放一个顶部导航栏和中的Fragment内容信息。留着后期大家功能扩展就可以。

3.主Activity使用例如以下:

  1. public class MainActivity extends BaseActivity {
  2. private DragLayout dl;
  3. private ListView lv;
  4. private ImageView iv_icon, iv_bottom;
  5. private QuickAdapter<ItemBean> quickAdapter;
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_main);
  10. setStatusBar();
  11. initDragLayout();
  12. initView();
  13.  
  14. }
  15. private void initDragLayout() {
  16. dl = (DragLayout) findViewById(R.id.dl);
  17. dl.setDragListener(new DragLayout.DragListener() {
  18. //界面打开的时候
  19. @Override
  20. public void onOpen() {
  21. }
  22. //界面关闭的时候
  23. @Override
  24. public void onClose() {
  25. }
  26.  
  27. //界面滑动的时候
  28. @Override
  29. public void onDrag(float percent) {
  30. ViewHelper.setAlpha(iv_icon, 1 - percent);
  31. }
  32. });
  33. }
  34.  
  35. private void initView() {
  36. iv_icon = (ImageView) findViewById(R.id.iv_icon);
  37. iv_bottom = (ImageView) findViewById(R.id.iv_bottom);
  38.  
  39. lv = (ListView) findViewById(R.id.lv);
  40. lv.setAdapter(quickAdapter=new QuickAdapter<ItemBean>(this,R.layout.item_left_layout, ItemDataUtils.getItemBeans()) {
  41. @Override
  42. protected void convert(BaseAdapterHelper helper, ItemBean item) {
  43. helper.setImageResource(R.id.item_img,item.getImg())
  44. .setText(R.id.item_tv,item.getTitle());
  45. }
  46. });
  47. lv.setOnItemClickListener(new OnItemClickListener() {
  48. @Override
  49. public void onItemClick(AdapterView<?> arg0, View arg1,
  50. int position, long arg3) {
  51. Toast.makeText(MainActivity.this,"Click Item "+position,Toast.LENGTH_SHORT).show();
  52. }
  53. });
  54. iv_icon.setOnClickListener(new OnClickListener() {
  55. @Override
  56. public void onClick(View arg0) {
  57. dl.open();
  58. }
  59. });
  60. }
  61.  
  62. }

初始化控件,设置滑动监听器,以及左側菜单功能列表设置就可以了,只是上面大家应该看了QuickAdapter的使用,该为BaseAdapterHelper框架使用,我们须要在项目build.gradle中作例如以下配置:

详细关于BaseAdapter的使用解说博客地址例如以下:

4.正式执行效果例如以下:

5.由于这边底层须要ViewDragHelper类,所以大家在使用的时候须要导入V4包的,只是我这边直接把ViewGragHelper类的源码拷贝到项目中了。

(六).DragLayout源码带凝视

上面主要分析DragLayout的详细实现。只是我这边也贴一下DragLayout带有凝视的全部源码让大家能够更好的了解DragLayout的详细实现代码:

  1. /**
  2. *使用ViewRragHelper实现側滑效果功能
  3. */
  4. publicclass DragLayout extends FrameLayout {
  5. private boolean isShowShadow = true;
  6. //手势处理类
  7. private GestureDetectorCompat gestureDetector;
  8. //视图拖拽移动帮助类
  9. private ViewDragHelper dragHelper;
  10. //滑动监听器
  11. private DragListener dragListener;
  12. //水平拖拽的距离
  13. private int range;
  14. //宽度
  15. private int width;
  16. //高度
  17. private int height;
  18. //main视图距离在ViewGroup距离左边的距离
  19. private int mainLeft;
  20. private Context context;
  21. private ImageView iv_shadow;
  22. //左側布局
  23. private RelativeLayout vg_left;
  24. //右側(主界面布局)
  25. private CustomRelativeLayout vg_main;
  26. //页面状态 默觉得关闭
  27. private Status status = Status.Close;
  28.  
  29. public DragLayout(Context context) {
  30. this(context, null);
  31. }
  32.  
  33. public DragLayout(Context context,AttributeSet attrs) {
  34. this(context, attrs, 0);
  35. this.context = context;
  36. }
  37.  
  38. public DragLayout(Context context,AttributeSet attrs, int defStyle) {
  39. super(context, attrs, defStyle);
  40. gestureDetector = new GestureDetectorCompat(context, new YScrollDetector());
  41. dragHelper =ViewDragHelper.create(this, dragHelperCallback);
  42. }
  43.  
  44. class YScrollDetector extends SimpleOnGestureListener {
  45. @Override
  46. public boolean onScroll(MotionEvent e1,MotionEvent e2, float dx, float dy) {
  47. return Math.abs(dy) <=Math.abs(dx);
  48. }
  49. }
  50. /**
  51. * 实现子View的拖拽滑动。实现Callback当中相关的方法
  52. */
  53. private ViewDragHelper.Callback dragHelperCallback = new ViewDragHelper.Callback() {
  54. /**
  55. * 水平方向移动
  56. * @param child Child view beingdragged
  57. * @param left Attempted motion alongthe X axis
  58. * @param dx Proposed change inposition for left
  59. * @return
  60. */
  61. @Override
  62. public int clampViewPositionHorizontal(View child, int left, int dx) {
  63. if (mainLeft + dx < 0) {
  64. return 0;
  65. } else if (mainLeft + dx >range) {
  66. return range;
  67. } else {
  68. return left;
  69. }
  70. }
  71.  
  72. /**
  73. * 拦截全部的子View
  74. * @param child Child the user isattempting to capture
  75. * @param pointerId ID of the pointerattempting the capture
  76. * @return
  77. */
  78. @Override
  79. public boolean tryCaptureView(View child, int pointerId) {
  80. return true;
  81. }
  82. /**
  83. * 设置水平方向滑动的最远距离
  84. *@param child Child view to check 屏幕宽度
  85. * @return
  86. */
  87. @Override
  88. public int getViewHorizontalDragRange(View child) {
  89. return width;
  90. }
  91.  
  92. /**
  93. * 当拖拽的子View,手势释放的时候回调的方法, 然后依据左滑或者右滑的距离进行推断打开或者关闭
  94. * @param releasedChild
  95. * @param xvel
  96. * @param yvel
  97. */
  98. @Override
  99. public void onViewReleased(View releasedChild, float xvel, float yvel) {
  100. super.onViewReleased(releasedChild,xvel, yvel);
  101. if (xvel > 0) {
  102. open();
  103. } else if (xvel < 0) {
  104. close();
  105. } else if (releasedChild == vg_main&& mainLeft > range * 0.3) {
  106. open();
  107. } else if (releasedChild == vg_left&& mainLeft > range * 0.7) {
  108. open();
  109. } else {
  110. close();
  111. }
  112. }
  113.  
  114. /**
  115. * 子View被拖拽 移动的时候回调的方法
  116. * @param changedView View whoseposition changed
  117. * @param left New X coordinate of theleft edge of the view
  118. * @param top New Y coordinate of thetop edge of the view
  119. * @param dx Change in X position fromthe last call
  120. * @param dy Change in Y position fromthe last call
  121. */
  122. @Override
  123. public void onViewPositionChanged(View changedView, int left, int top,
  124. int dx, int dy) {
  125. if (changedView == vg_main) {
  126. mainLeft = left;
  127. } else {
  128. mainLeft = mainLeft + left;
  129. }
  130. if (mainLeft < 0) {
  131. mainLeft = 0;
  132. } else if (mainLeft > range) {
  133. mainLeft = range;
  134. }
  135.  
  136. if (isShowShadow) {
  137. iv_shadow.layout(mainLeft, 0,mainLeft + width, height);
  138. }
  139. if (changedView == vg_left) {
  140. vg_left.layout(0, 0, width,height);
  141. vg_main.layout(mainLeft, 0,mainLeft + width, height);
  142. }
  143.  
  144. dispatchDragEvent(mainLeft);
  145. }
  146. };
  147.  
  148. /**
  149. * 滑动相关回调接口
  150. */
  151. public interface DragListener {
  152. //界面打开
  153. public void onOpen();
  154. //界面关闭
  155. public void onClose();
  156. //界面滑动过程中
  157. public void onDrag(float percent);
  158. }
  159. public void setDragListener(DragListener dragListener) {
  160. this.dragListener = dragListener;
  161. }
  162.  
  163. /**
  164. * 布局载入完毕回调
  165. * 做一些初始化的操作
  166. */
  167. @Override
  168. protected void onFinishInflate() {
  169. super.onFinishInflate();
  170. if (isShowShadow) {
  171. iv_shadow = new ImageView(context);
  172. iv_shadow.setImageResource(R.mipmap.shadow);
  173. LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
  174. addView(iv_shadow, 1, lp);
  175. }
  176. //左側界面
  177. vg_left = (RelativeLayout)getChildAt(0);
  178. //右側(主)界面
  179. vg_main = (CustomRelativeLayout)getChildAt(isShowShadow ? 2 : 1);
  180. vg_main.setDragLayout(this);
  181. vg_left.setClickable(true);
  182. vg_main.setClickable(true);
  183. }
  184.  
  185. public ViewGroup getVg_main() {
  186. return vg_main;
  187. }
  188.  
  189. public ViewGroup getVg_left() {
  190. return vg_left;
  191. }
  192.  
  193. @Override
  194. protected void onSizeChanged(int w, int h,int oldw, int oldh) {
  195. super.onSizeChanged(w, h, oldw, oldh);
  196. width = vg_left.getMeasuredWidth();
  197. height = vg_left.getMeasuredHeight();
  198. //能够水平拖拽滑动的距离 一共为屏幕宽度的80%
  199. range = (int) (width * 0.8f);
  200. }
  201.  
  202. /**
  203. * 调用进行left和main 视图进行位置布局
  204. * @param changed
  205. * @param left
  206. * @param top
  207. * @param right
  208. * @param bottom
  209. */
  210. @Override
  211. protected void onLayout(boolean changed,int left, int top, int right, int bottom) {
  212. vg_left.layout(0, 0, width, height);
  213. vg_main.layout(mainLeft, 0, mainLeft +width, height);
  214. }
  215.  
  216. /**
  217. * 拦截触摸事件
  218. * @param ev
  219. * @return
  220. */
  221. @Override
  222. public boolean onInterceptTouchEvent(MotionEvent ev) {
  223. returndragHelper.shouldInterceptTouchEvent(ev) &&gestureDetector.onTouchEvent(ev);
  224. }
  225.  
  226. /**
  227. * 将拦截的到事件给ViewDragHelper进行处理
  228. * @param e
  229. * @return
  230. */
  231. @Override
  232. public boolean onTouchEvent(MotionEvent e){
  233. try {
  234. dragHelper.processTouchEvent(e);
  235. } catch (Exception ex) {
  236. ex.printStackTrace();
  237. }
  238. return false;
  239. }
  240.  
  241. /**
  242. * 进行处理拖拽事件
  243. * @param mainLeft
  244. */
  245. private void dispatchDragEvent(intmainLeft) {
  246. if (dragListener == null) {
  247. return;
  248. }
  249. float percent = mainLeft / (float)range;
  250. //滑动动画效果
  251. animateView(percent);
  252. //进行回调滑动的百分比
  253. dragListener.onDrag(percent);
  254. Status lastStatus = status;
  255. if (lastStatus != getStatus()&& status == Status.Close) {
  256. dragListener.onClose();
  257. } else if (lastStatus != getStatus()&& status == Status.Open) {
  258. dragListener.onOpen();
  259. }
  260. }
  261.  
  262. /**
  263. * 依据滑动的距离的比例,进行平移动画
  264. * @param percent
  265. */
  266. private void animateView(float percent) {
  267. float f1 = 1 - percent * 0.5f;
  268.  
  269. ViewHelper.setTranslationX(vg_left,-vg_left.getWidth() / 2.5f + vg_left.getWidth() / 2.5f * percent);
  270. if (isShowShadow) {
  271. //阴影效果视图大小进行缩放
  272. ViewHelper.setScaleX(iv_shadow, f1* 1.2f * (1 - percent * 0.10f));
  273. ViewHelper.setScaleY(iv_shadow, f1* 1.85f * (1 - percent * 0.10f));
  274. }
  275. }
  276. /**
  277. * 有加速度,当我们停止滑动的时候,该不会马上停止动画效果
  278. */
  279. @Override
  280. public void computeScroll() {
  281. if (dragHelper.continueSettling(true)){
  282. ViewCompat.postInvalidateOnAnimation(this);
  283. }
  284. }
  285.  
  286. /**
  287. * 页面状态(滑动,打开,关闭)
  288. */
  289. public enum Status {
  290. Drag, Open, Close
  291. }
  292.  
  293. /**
  294. * 页面状态设置
  295. * @return
  296. */
  297. public Status getStatus() {
  298. if (mainLeft == 0) {
  299. status = Status.Close;
  300. } else if (mainLeft == range) {
  301. status = Status.Open;
  302. } else {
  303. status = Status.Drag;
  304. }
  305. return status;
  306. }
  307.  
  308. public void open() {
  309. open(true);
  310. }
  311.  
  312. public void open(boolean animate) {
  313. if (animate) {
  314. //继续滑动
  315. if(dragHelper.smoothSlideViewTo(vg_main, range, 0)) {
  316. ViewCompat.postInvalidateOnAnimation(this);
  317. }
  318. } else {
  319. vg_main.layout(range, 0, range * 2,height);
  320. dispatchDragEvent(range);
  321. }
  322. }
  323.  
  324. public void close() {
  325. close(true);
  326. }
  327.  
  328. public void close(boolean animate) {
  329. if (animate) {
  330. //继续滑动
  331. if(dragHelper.smoothSlideViewTo(vg_main, 0, 0)) {
  332. ViewCompat.postInvalidateOnAnimation(this);
  333. }
  334. } else {
  335. vg_main.layout(0, 0, width,height);
  336. dispatchDragEvent(0);
  337. }
  338. }
  339. }

(七).最后总结

今天我们实现打造QQ最新版本号QQ6.X效果。同一时候里边用到了ViewDragHelper,BaseAdapterHelper的运用。详细该知识点的用法,我已经在我的博客中更新解说的文章,欢迎大家查看。

本次详细实例凝视过的全部代码已经上传到Github项目中了。同一时候欢迎大家去Github站点进行clone或者下载浏览:

https://github.com/jiangqqlmj/DragHelper4QQ

同一时候欢迎大家star和fork整个开源高速开发框架项目~

本例所用其它知识点博文地址例如以下:

特别致谢DragLayout组件开发人员:https://github.com/BlueMor/DragLayout

尊重原创,转载请注明:From Sky丶清(http://blog.csdn.net/developer_jiangqq) 侵权必究!

关注我的订阅号,每天分享移动开发技术(Android/IOS),项目管理以及博客文章!

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

关注我的微博,能够获得很多其它精彩内容

【FastDev4Android框架开发】打造QQ6.X最新版本号側滑界面效果(三十八)的更多相关文章

  1. 【FastDev4Android框架开发】RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout(三十一)

    转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/49992269 本文出自:[江清清的博客] (一).前言: [好消息] ...

  2. 应用程序框架实战三十八:项目示例VS解决方案的创建(一)

    进行项目开发的第一步,是创建出适合自己团队习惯的VS解决方案,虽然我已经提供了项目示例,但毕竟是我创建的,你直接使用可能并不合适,另外你如果尝试模仿重新创建该示例,中间可能碰到各种障碍,特别是项目间的 ...

  3. Android项目实战(三十八):2017最新 将AndroidLibrary提交到JCenter仓库(图文教程)

    我们经常使用github上的开源项目,使用步骤也很简单 比如: compile 'acffo.xqx.xwaveviewlib:maven:1.0.0' 这里就学习一下如何将自己的类库做出这种可以供他 ...

  4. Unity 游戏框架搭建 2019 (三十六~三十八) partial与public

    在上一篇,我们把菜单的顺序从头到尾整理了一遍.在整理菜单顺序的过程中,记录了一个要做的事情. 要做的事情: (完成) 备份:导出文件,并取一个合理的名字. 整理完菜单顺序后,学习新的知识,解决随着示例 ...

  5. 网站开发进阶(三十八)Web前端开发规范文档你需要知道的事

    Web前端开发规范文档你需要知道的事 规范目的 为提高团队协作效率, 便于后台人员添加功能及前端后期优化维护, 输出高质量的文档, 特制订此文档. 本规范文档一经确认, 前端开发人员必须按本文档规范进 ...

  6. BizTalk开发系列(三十八)微软BizTalk Server定价和许可[解读]

    做BizTalk的项目一段时间了,但是对BizTalk的价格和许可还不是很了解.给客户设计解决方案时大部分产品都是直接按照企业版的功能来设计,很 少考虑到价格和许可方面的因素,以为这个不是我们的事情或 ...

  7. Java开发笔记(一百三十八)JavaFX的箱子

    前面介绍了JavaFX标签控件的用法,其中提到Label文本支持中文字体,那么它到底支持哪些中文字体呢?自然要看当前的操作系统都安装了哪些字体才行,对于中文的Windows系统,默认安装了黑体“Sim ...

  8. Dynamic CRM 2013学习笔记(三十八)流程1 - 操作(action)开发与配置详解

    CRM 2013 里流程有4个类别:操作(action).业务流程(business process flow).对话(dialog)和工作流(workflow).它们都是从 setting –> ...

  9. Java开发笔记(三十八)利用正则表达式校验字符串

    前面多次提到了正则串.正则表达式,那么正则表达式究竟是符合什么定义的字符串呢?正则表达式是编程语言处理字符串格式的一种逻辑式子,它利用若干保留字符定义了形形色色的匹配规则,从而通过一个式子来覆盖满足了 ...

随机推荐

  1. 阿里云centos系统上安装ftp

    最近需要在一台阿里云的云服务器上搭建FTP服务器,在这篇博文中分享一下我们根据实际需求进行的一些配置. ftp软件用的是vsftpd. vsftpd是一款在Linux发行版中最受推崇的FTP服务器程序 ...

  2. Django day05 视图层之 (HttpRequest) \ (HttpResponse) \ (JsonResponse) 对象

    一:视图层之HttpRequest对象 # 前台Post传过来的数据,包装到POST字典中 # request.POST # 前台浏览器窗口里携带的数据,包装到GET字典中 # request.GET ...

  3. Android Fragment与Activity交互的几种方式

    这里我不再详细介绍那写比较常规的方式,例如静态变量,静态方法,持久化,application全局变量,收发广播等等. 首先我们来介绍使用Handler来实现Fragment与Activity 的交互. ...

  4. 【Oracle】解锁用户

    登录oracle数据库时有时会显示ERROR: ORA-28000: the account is locked,这是因为所登录的账号被锁定了. 解决办法: sqlplus / as sysdba; ...

  5. Mongo连接远程数据库

    mongo IP+Port CrabyterV5 首先这么操作是基于配置了环境变量的,可以参照http://www.cnblogs.com/daiyonghui/p/5209076.html mong ...

  6. HIVE 命令记录

    HIVE 命令记录 设置hive运行的队列 hive> set mapreduce.job.queuename=ven12; 打印列名 hive> set hive.cli.print.h ...

  7. Windows 10 新功能

    一.与 Cortana 集成的便笺 借助便笺,你可捕捉并保存绝妙创意或记录重要细节.便笺现已与 Cortana 集成,让你能够设置整个设备中的提醒. (一)   先来了解一下微软小娜Cortana. ...

  8. 编译Caffe-Win错误集锦

    Caffe在Windows下编译还是遇到不少麻烦的... 1.visual studio 2013 error C2371: 'int8_t' : redefinition; 引入的unistd.h文 ...

  9. matlab中 注意事项--字符串

    Matlab中的字符串操作 原文链接:http://hi.baidu.com/dreamflyman/item/bd6d8224430003c9a5275a9f (1).字符串是以ASCII码形式存储 ...

  10. 【JSP】上传图片到数据库中

    第一步:建立数据库 create table test_img(id number(4),name varchar(20),img long raw); 第二步:(NewImg.html) <h ...