Android使用ViewDragHelper实现QQ6.X最新版本侧滑界面效果实例代码

(一).前言:

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

本次实例具体代码已经上传到下面的项目中,欢迎各位去star和fork一下。

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

(二).ViewGragHelper的基本使用

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

创建ViewGragHelper实例(传入Callback)

重写事件拦截处理方法onInterceptTouch和onTouchEvent

实现Callback,实现其中的相关方法tryCaptureView以及水平或者垂直方向移动的距离方法

更加具体分析大家可以看前一篇博客,或者我们今天这边会通过具体实例讲解一下。

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

在正式版本QQ中的侧滑效果如下:

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

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

1.首先我们这边集成自FrameLayout创建一个自定义View DragLayout。内部的定义的一些变量如下(主要包括一些配置类,手势,ViewDragHelper实例,屏幕宽高,拖拽的子视图View等)

//是否带有阴影效果 private boolean isShowShadow = true; //手势处理类 private GestureDetectorCompat gestureDetector; //视图拖拽移动帮助类 private ViewDragHelper dragHelper; //滑动监听器 private DragListener dragListener; //水平拖拽的距离 private int range; //宽度 private int width; //高度 private int height; //main视图距离在ViewGroup距离左边的距离 private int mainLeft; private Context context; private ImageView iv_shadow; //左侧布局 private RelativeLayout vg_left; //右侧(主界面布局) private CustomRelativeLayout vg_main;

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

/** * 滑动相关回调接口 */ public interface DragListener { //界面打开 public void onOpen(); //界面关闭 public void onClose(); //界面滑动过程中 public void onDrag(float percent); }

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

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

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

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

/** * 拦截触摸事件 * @param ev * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return dragHelper.shouldInterceptTouchEvent(ev) &&gestureDetector.onTouchEvent(ev); } /** * 将拦截的到事件给ViewDragHelper进行处理 * @param e * @return */ @Override public boolean onTouchEvent(MotionEvent e){ try { dragHelper.processTouchEvent(e); } catch (Exception ex) { ex.printStackTrace(); } return false; }

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

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

/** * 拦截所有的子View * @param child Child the user is attempting to capture * @param pointerId ID of the pointer attempting the capture * @return */ @Override public boolean tryCaptureView(Viewchild, int pointerId) { return true; }

该进行拦截ViewGroup(本例中为:DragLayout)中所有的子View,直接返回true,表示所有的子View都可以进行拖拽移动。

/** * 水平方向移动 * @param child Child view beingdragged * @param left Attempted motion alongthe X axis * @param dx Proposed change inposition for left * @return */ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if (mainLeft + dx < 0) { return 0; } else if (mainLeft + dx >range) { return range; } else { return left; } }

实现该方法表示水平方向滑动,同时方法中会进行判断边界值,例如当上面的main view已经向左移动边界之外了,直接返回0,表示向左最左边只能x=0;然后向右移动会判断向右最变得距离range,至于range的初始化后边会讲到。除了这两种情况之外,就是直接返回left即可。

/** * 设置水平方向滑动的最远距离 *@param child Child view to check 屏幕宽度 * @return */ @Override public int getViewHorizontalDragRange(View child) { return width; }

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

/** * 当拖拽的子View,手势释放的时候回调的方法, 然后根据左滑或者右滑的距离进行判断打开或者关闭 * @param releasedChild * @param xvel * @param yvel */ @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild,xvel, yvel); if (xvel > 0) { open(); } else if (xvel < 0) { close(); } else if (releasedChild == vg_main&& mainLeft > range * 0.3) { open(); } else if (releasedChild == vg_left&& mainLeft > range * 0.7) { open(); } else { close(); } }

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

/** * 子View被拖拽 移动的时候回调的方法 * @param changedView View whoseposition changed * @param left New X coordinate of theleft edge of the view * @param top New Y coordinate of thetop edge of the view * @param dx Change in X position fromthe last call * @param dy Change in Y position fromthe last call */ @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { if (changedView == vg_main) { mainLeft = left; } else { mainLeft = mainLeft + left; } if (mainLeft < 0) { mainLeft = 0; } else if (mainLeft > range) { mainLeft = range; } if (isShowShadow) { iv_shadow.layout(mainLeft, 0,mainLeft + width, height); } if (changedView == vg_left) { vg_left.layout(0, 0, width,height); vg_main.layout(mainLeft, 0,mainLeft + width, height); } dispatchDragEvent(mainLeft); } };

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

/** * 进行处理拖拽事件 * @param mainLeft */ private void dispatchDragEvent(int mainLeft) { if (dragListener == null) { return; } float percent = mainLeft / (float)range; //根据滑动的距离的比例 animateView(percent); //进行回调滑动的百分比 dragListener.onDrag(percent); Status lastStatus = status; if (lastStatus != getStatus()&& status == Status.Close) { dragListener.onClose(); } else if (lastStatus != getStatus()&& status == Status.Open) { dragListener.onOpen(); } }

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

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

/** * 布局加载完成回调 * 做一些初始化的操作 */ @Override protected void onFinishInflate() { super.onFinishInflate(); if (isShowShadow) { iv_shadow = new ImageView(context); iv_shadow.setImageResource(R.mipmap.shadow); LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); addView(iv_shadow, 1, lp); } //左侧界面 vg_left = (RelativeLayout)getChildAt(0); //右侧(主)界面 vg_main = (CustomRelativeLayout)getChildAt(isShowShadow ? 2 : 1); vg_main.setDragLayout(this); vg_left.setClickable(true); vg_main.setClickable(true); }

以及控件大小发生变化回调的方法:

@Override protected void onSizeChanged(int w, int h,int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); width = vg_left.getMeasuredWidth(); height = vg_left.getMeasuredHeight(); //可以水平拖拽滑动的距离 一共为屏幕宽度的80% range = (int) (width *0.8f); }

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

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

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

/** * 根据滑动的距离的比例,进行平移动画 * @param percent */ private void animateView(float percent) { float f1 = 1 - percent * 0.5f; ViewHelper.setTranslationX(vg_left,-vg_left.getWidth() / 2.5f + vg_left.getWidth() / 2.5f * percent); if (isShowShadow) { //阴影效果视图大小进行缩放 ViewHelper.setScaleX(iv_shadow, f1* 1.2f * (1 - percent * 0.10f)); ViewHelper.setScaleY(iv_shadow, f1* 1.85f * (1 - percent * 0.10f)); } }

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

/** * 有加速度,当我们停止滑动的时候,该不会立即停止动画效果 */ @Override public void computeScroll() { if (dragHelper.continueSettling(true)){ ViewCompat.postInvalidateOnAnimation(this); } }

OK上面关于DragLayout的核心代码就差不多这么多了,下面是使用DragLayout类来实现侧滑效果啦!

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

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

<com.chinaztt.widget.DragLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/dl" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" > <!--下层 左边的布局--> <includelayoutincludelayout="@layout/left_view_layout"/> <!--上层 右边的主布局--> <com.chinaztt.widget.CustomRelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" > <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <RelativeLayout android:id="@+id/rl_title" android:layout_width="match_parent" android:layout_height="49dp" android:gravity="bottom" android:background="@android:color/holo_orange_light" > <includelayoutincludelayout="@layout/common_top_bar_layout"/> </RelativeLayout> <!--中间内容后面放入Fragment--> <FrameLayout android:layout_width="fill_parent" android:layout_height="fill_parent" > <fragment android:id="@+id/main_info_fragment" class="com.chinaztt.fragment.OneFragment" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </FrameLayout> </LinearLayout> </com.chinaztt.widget.CustomRelativeLayout> </com.chinaztt.widget.DragLayout>

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

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

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingTop="70dp" android:background="@drawable/sidebar_bg" > <LinearLayout android:id="@+id/ll1" android:paddingLeft="30dp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!--头像,昵称信息--> <LinearLayout android:layout_width="match_parent" android:layout_height="70dp" android:orientation="horizontal" android:gravity="center_vertical" > <com.chinaztt.widget.RoundAngleImageView android:id="@+id/iv_bottom" android:layout_width="50dp" android:layout_height="50dp" android:scaleType="fitXY" android:src="@drawable/icon_logo" app:roundWidth="25dp" app:roundHeight="25dp"/> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:layout_gravity="center_vertical" android:orientation="vertical"> <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="15dp" android:text="名字:jiangqqlmj" android:textColor="@android:color/black" android:textSize="15sp" /> <ImageButton android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="100dp" android:layout_width="22dp" android:layout_height="22dp" android:background="@drawable/qrcode_selector"/> </RelativeLayout> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="15dp" android:text="QQ:781931404" android:textColor="@android:color/black" android:textSize="13sp" /> </LinearLayout> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="horizontal"> <ImageView android:layout_width="17dp" android:layout_height="17dp" android:scaleType="fitXY" android:src="@drawable/sidebar_signature_nor"/> <TextView android:layout_marginLeft="5dp" android:textSize="13sp" android:textColor="#676767" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="用心做产品!"/> </LinearLayout> </LinearLayout> <!--底部功能条--> <includelayoutincludelayout="@layout/left_view_bottom_layout" android:id="@+id/bottom_view" /> <!--中间列表--> <ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@id/bottom_view" android:layout_below="@id/ll1" android:layout_marginBottom="30dp" android:layout_marginTop="70dp" android:cacheColorHint="#00000000" android:listSelector="@drawable/lv_click_selector" android:divider="@null" android:scrollbars="none" android:textColor="#ffffff"/> </RelativeLayout>

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

3.主Activity使用如下:

public class MainActivity extends BaseActivity { private DragLayout dl; private ListView lv; private ImageView iv_icon, iv_bottom; private QuickAdapter<ItemBean> quickAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setStatusBar(); initDragLayout(); initView(); } private void initDragLayout() { dl = (DragLayout) findViewById(R.id.dl); dl.setDragListener(new DragLayout.DragListener() { //界面打开的时候 @Override public void onOpen() { } //界面关闭的时候 @Override public void onClose() { } //界面滑动的时候 @Override public void onDrag(float percent) { ViewHelper.setAlpha(iv_icon, 1 - percent); } }); } private void initView() { iv_icon = (ImageView) findViewById(R.id.iv_icon); iv_bottom = (ImageView) findViewById(R.id.iv_bottom); lv = (ListView) findViewById(R.id.lv); lv.setAdapter(quickAdapter=new QuickAdapter<ItemBean>(this,R.layout.item_left_layout, ItemDataUtils.getItemBeans()) { @Override protected void convert(BaseAdapterHelper helper, ItemBean item) { helper.setImageResource(R.id.item_img,item.getImg()) .setText(R.id.item_tv,item.getTitle()); } }); lv.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) { Toast.makeText(MainActivity.this,"Click Item "+position,Toast.LENGTH_SHORT).show(); } }); iv_icon.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { dl.open(); } }); } }

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

具体关于BaseAdapter的使用讲解博客地址如下:

4.正式运行效果如下:

5.因为这边底层需要ViewDragHelper类,所以大家在使用的时候需要导入V4包的,不过我这边直接把ViewGragHelper类的源代码复制到项目中了。

(六).DragLayout源代码带注释

上面主要分析DragLayout的具体实现,不过我这边也贴一下DragLayout带有注释的全部源代码让大家可以更好的了解DragLayout的具体实现代码:

/** *使用ViewRragHelper实现侧滑效果功能 */ publicclass DragLayout extends FrameLayout { private boolean isShowShadow = true; //手势处理类 private GestureDetectorCompat gestureDetector; //视图拖拽移动帮助类 private ViewDragHelper dragHelper; //滑动监听器 private DragListener dragListener; //水平拖拽的距离 private int range; //宽度 private int width; //高度 private int height; //main视图距离在ViewGroup距离左边的距离 private int mainLeft; private Context context; private ImageView iv_shadow; //左侧布局 private RelativeLayout vg_left; //右侧(主界面布局) private CustomRelativeLayout vg_main; //页面状态 默认为关闭 private Status status = Status.Close; public DragLayout(Context context) { this(context, null); } public DragLayout(Context context,AttributeSet attrs) { this(context, attrs, 0); this.context = context; } public DragLayout(Context context,AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); gestureDetector = new GestureDetectorCompat(context, new YScrollDetector()); dragHelper =ViewDragHelper.create(this, dragHelperCallback); } class YScrollDetector extends SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1,MotionEvent e2, float dx, float dy) { return Math.abs(dy) <=Math.abs(dx); } } /** * 实现子View的拖拽滑动,实现Callback当中相关的方法 */ private ViewDragHelper.Callback dragHelperCallback = new ViewDragHelper.Callback() { /** * 水平方向移动 * @param child Child view beingdragged * @param left Attempted motion alongthe X axis * @param dx Proposed change inposition for left * @return */ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if (mainLeft + dx < 0) { return 0; } else if (mainLeft + dx >range) { return range; } else { return left; } } /** * 拦截所有的子View * @param child Child the user isattempting to capture * @param pointerId ID of the pointerattempting the capture * @return */ @Override public boolean tryCaptureView(View child, int pointerId) { return true; } /** * 设置水平方向滑动的最远距离 *@param child Child view to check 屏幕宽度 * @return */ @Override public int getViewHorizontalDragRange(View child) { return width; } /** * 当拖拽的子View,手势释放的时候回调的方法, 然后根据左滑或者右滑的距离进行判断打开或者关闭 * @param releasedChild * @param xvel * @param yvel */ @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild,xvel, yvel); if (xvel > 0) { open(); } else if (xvel < 0) { close(); } else if (releasedChild == vg_main&& mainLeft > range * 0.3) { open(); } else if (releasedChild == vg_left&& mainLeft > range * 0.7) { open(); } else { close(); } } /** * 子View被拖拽 移动的时候回调的方法 * @param changedView View whoseposition changed * @param left New X coordinate of theleft edge of the view * @param top New Y coordinate of thetop edge of the view * @param dx Change in X position fromthe last call * @param dy Change in Y position fromthe last call */ @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { if (changedView == vg_main) { mainLeft = left; } else { mainLeft = mainLeft + left; } if (mainLeft < 0) { mainLeft = 0; } else if (mainLeft > range) { mainLeft = range; } if (isShowShadow) { iv_shadow.layout(mainLeft, 0,mainLeft + width, height); } if (changedView == vg_left) { vg_left.layout(0, 0, width,height); vg_main.layout(mainLeft, 0,mainLeft + width, height); } dispatchDragEvent(mainLeft); } }; /** * 滑动相关回调接口 */ public interface DragListener { //界面打开 public void onOpen(); //界面关闭 public void onClose(); //界面滑动过程中 public void onDrag(float percent); } public void setDragListener(DragListener dragListener) { this.dragListener = dragListener; } /** * 布局加载完成回调 * 做一些初始化的操作 */ @Override protected void onFinishInflate() { super.onFinishInflate(); if (isShowShadow) { iv_shadow = new ImageView(context); iv_shadow.setImageResource(R.mipmap.shadow); LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); addView(iv_shadow, 1, lp); } //左侧界面 vg_left = (RelativeLayout)getChildAt(0); //右侧(主)界面 vg_main = (CustomRelativeLayout)getChildAt(isShowShadow ? 2 : 1); vg_main.setDragLayout(this); vg_left.setClickable(true); vg_main.setClickable(true); } public ViewGroup getVg_main() { return vg_main; } public ViewGroup getVg_left() { return vg_left; } @Override protected void onSizeChanged(int w, int h,int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); width = vg_left.getMeasuredWidth(); height = vg_left.getMeasuredHeight(); //可以水平拖拽滑动的距离 一共为屏幕宽度的80% range = (int) (width * 0.8f); } /** * 调用进行left和main 视图进行位置布局 * @param changed * @param left * @param top * @param right * @param bottom */ @Override protected void onLayout(boolean changed,int left, int top, int right, int bottom) { vg_left.layout(0, 0, width, height); vg_main.layout(mainLeft, 0, mainLeft +width, height); } /** * 拦截触摸事件 * @param ev * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { returndragHelper.shouldInterceptTouchEvent(ev) &&gestureDetector.onTouchEvent(ev); } /** * 将拦截的到事件给ViewDragHelper进行处理 * @param e * @return */ @Override public boolean onTouchEvent(MotionEvent e){ try { dragHelper.processTouchEvent(e); } catch (Exception ex) { ex.printStackTrace(); } return false; } /** * 进行处理拖拽事件 * @param mainLeft */ private void dispatchDragEvent(intmainLeft) { if (dragListener == null) { return; } float percent = mainLeft / (float)range; //滑动动画效果 animateView(percent); //进行回调滑动的百分比 dragListener.onDrag(percent); Status lastStatus = status; if (lastStatus != getStatus()&& status == Status.Close) { dragListener.onClose(); } else if (lastStatus != getStatus()&& status == Status.Open) { dragListener.onOpen(); } } /** * 根据滑动的距离的比例,进行平移动画 * @param percent */ private void animateView(float percent) { float f1 = 1 - percent * 0.5f; ViewHelper.setTranslationX(vg_left,-vg_left.getWidth() / 2.5f + vg_left.getWidth() / 2.5f * percent); if (isShowShadow) { //阴影效果视图大小进行缩放 ViewHelper.setScaleX(iv_shadow, f1* 1.2f * (1 - percent * 0.10f)); ViewHelper.setScaleY(iv_shadow, f1* 1.85f * (1 - percent * 0.10f)); } } /** * 有加速度,当我们停止滑动的时候,该不会立即停止动画效果 */ @Override public void computeScroll() { if (dragHelper.continueSettling(true)){ ViewCompat.postInvalidateOnAnimation(this); } } /** * 页面状态(滑动,打开,关闭) */ public enum Status { Drag, Open, Close } /** * 页面状态设置 * @return */ public Status getStatus() { if (mainLeft == 0) { status = Status.Close; } else if (mainLeft == range) { status = Status.Open; } else { status = Status.Drag; } return status; } public void open() { open(true); } public void open(boolean animate) { if (animate) { //继续滑动 if(dragHelper.smoothSlideViewTo(vg_main, range, 0)) { ViewCompat.postInvalidateOnAnimation(this); } } else { vg_main.layout(range, 0, range * 2,height); dispatchDragEvent(range); } } public void close() { close(true); } public void close(boolean animate) { if (animate) { //继续滑动 if(dragHelper.smoothSlideViewTo(vg_main, 0, 0)) { ViewCompat.postInvalidateOnAnimation(this); } } else { vg_main.layout(0, 0, width,height); dispatchDragEvent(0); } } }

(七).最后总结

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

时间: 2024-10-15 15:24:10

Android使用ViewDragHelper实现QQ6.X最新版本侧滑界面效果实例代码的相关文章

Android使用ViewDragHelper实现QQ6.X最新版本侧滑界面效果实例代码_Android

(一).前言: 这两天QQ进行了重大更新(6.X)尤其在UI风格上面由之前的蓝色换成了白色居多了,侧滑效果也发生了一些变化,那我们今天来模仿实现一个QQ6.X版本的侧滑界面效果.今天我们还是采用神器ViewDragHelper来实现. 本次实例具体代码已经上传到下面的项目中,欢迎各位去star和fork一下. https://github.com/jiangqqlmj/DragHelper4QQ FastDev4Android框架项目地址:https://github.com/jiangqqlm

Android 自定义 HorizontalScrollView 打造多图片OOM 的横向滑动效果(实例代码)

自从Gallery被谷歌废弃以后,Google推荐使用ViewPager和HorizontalScrollView来实现Gallery的效果.的确HorizontalScrollView可以实现Gallery的效果,但是HorizontalScrollView存在一个很大的问题,如果你仅是用来展示少量的图片,应该是没问题的,但是如果我希望HorizontalScrollView可以想ViewPager一样,既可以绑定数据集(动态改变图片),还能做到,不管多少图片都不会OOM(ViewPager内

Android自定义view系列之99.99%实现QQ侧滑删除效果实例代码详解

首先声明本文是基于GitHub上"baoyongzhang"的SwipeMenuListView修改而来,该项目地址: https://github.com/baoyongzhang/SwipeMenuListView 可以说这个侧滑删除效果是我见过效果最好且比较灵活的项目,没有之一!!! 但是在使用它之前需要给大家提两点注意事项: 1,该项目支持Gradle dependence,但是目前作者提供的依赖地址对应的项目不是最新的项目,依赖过后的代码与demo中使用的不一致,会提示没有B

Android自定义手机界面状态栏实例代码

前言 我们知道IOS上的应用,状态栏的颜色总能与应用标题栏颜色保持一致,用户体验很不错,那安卓是否可以呢?若是在安卓4.4之前,答案是否定的,但在4.4之后,谷歌允许开发者自定义状态栏背景颜色啦,这是个不错的体验!若你手机上安装有最新版的qq,并且你的安卓SDK版本是4.4及以上,你可以看下它的效果: 实现这个效果有两个方法: 1.在xml中设置主题或自定义style: Theme.Holo.Light.NoActionBar.TranslucentDecor Theme.Holo.NoActi

Android 使用Fragment模仿微信界面的实例代码

什么是Fragment 自从Android 3.0中引入fragments 的概念,根据词海的翻译可以译为:碎片.片段.其目的是为了解决不同屏幕分辩率的动态和灵活UI设计.大屏幕如平板小屏幕如手机,平板电脑的设计使得其有更多的空间来放更多的UI组件,而多出来的空间存放UI使其会产生更多的交互,从而诞生了fragments . fragments 的设计不需要你来亲自管理view hierarchy 的复杂变化,通过将Activity 的布局分散到frament 中,可以在运行时修改activit

Android 从底部弹出Dialog(横向满屏)的实例代码_Android

项目中经常需要底部弹出框,这里我整理一下其中我用的比较顺手的一个方式(底部弹出一个横向满屏的dialog). 效果图如下所示(只显示关键部分): 步骤如下所示: 1.定义一个dialog的布局(lay_share.xml) <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/androi

Android 动态改变SeekBar进度条颜色与滑块颜色的实例代码_Android

遇到个动态改变SeekBar进度条颜色与滑块颜色的需求,有的是根据不同进度改变成不同颜色. 对于这个怎么做呢?大家都知道设置下progressDrawable与thumb即可,但是这样设置好就是确定的了,要动态更改需要在代码里实现. 用shape进度条与滑块 SeekBar设置 代码里动态设置setProgressDrawable与setThumb 画图形,大家都比较熟悉,background是背景图,secondaryProgress第二进度条,progress进度条: <layer-list

Android 仿今日头条简单的刷新效果实例代码_Android

点击按钮,先自动进行下拉刷新,也可以手动刷新,刷新完后,最后就多一行数据.有四个选项卡. 前两天导师要求做一个给本科学生预定机房座位的app,出发点来自这里.做着做着遇到很多问题,都解决了.这个效果感觉还不错,整理一下. MainActivity package com.example.fragmentmytest; import android.content.DialogInterface; import android.graphics.Color; import android.os.B

Android 从底部弹出Dialog(横向满屏)的实例代码

项目中经常需要底部弹出框,这里我整理一下其中我用的比较顺手的一个方式(底部弹出一个横向满屏的dialog). 效果图如下所示(只显示关键部分): 步骤如下所示: 1.定义一个dialog的布局(lay_share.xml) <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/androi