Home > Java > javaTutorial > Android uses ViewDragHelper to implement the latest version of QQ6.X side-sliding interface effect example code

Android uses ViewDragHelper to implement the latest version of QQ6.X side-sliding interface effect example code

高洛峰
Release: 2017-01-13 10:29:56
Original
1309 people have browsed it

(1). Foreword:

QQ has undergone a major update in the past two days (6. Some changes have been made, so today we will imitate and implement the side-sliding interface effect of the QQ6.X version. Today we still use the artifact ViewDragHelper to implement it.

The specific code of this example has been uploaded to the following project. You are welcome to star and fork it.

https://github.com/jiangqqlmj/DragHelper4QQ
FastDev4Android framework project address: https://github.com/jiangqqlmj/FastDev4Android

(二).Basic use of ViewGragHelper

Earlier we learned the basic use of ViewGragHelper, and also knew the uses of several methods inside. Let's review the basic usage steps. The steps to use ViewGragHelper to implement drag-and-drop movement of sub-Views are as follows:

Create a ViewGragHelper instance (pass in Callback)

Rewrite the event interception processing methods onInterceptTouch and onTouchEvent

Implement Callback, implement the related methods tryCaptureView and the distance method of horizontal or vertical movement

For more detailed analysis, you can read the previous blog, or we will pass the detailed analysis here today. Explain with examples.

(3).Analysis on implementation of sideslip effect in QQ5.X:

The sideslip effect in the official version of QQ is as follows:

Android uses ViewDragHelper to implement the latest version of QQ6.X side-sliding interface effect example code

Observing the above, we can understand it as two Views, one is the bottom function View equivalent to the left side, and the other is the upper main function content View. When we drag the upper View above or slide left and right, the upper and The lower View slides and the View size changes accordingly, and relevant animations are added. Of course, we can click on the upper View to open or close the side-sliding menu.

(4). Implementation of custom component for side sliding effect

1. First, we integrate FrameLayout to create a custom View DragLayout. Some variables defined internally are as follows (mainly including some configuration classes, gestures, ViewDragHelper instances, screen width and height, dragging subview View, etc.)

//是否带有阴影效果 
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;
Copy after login

Then a callback interface is also defined internally to mainly handle dragging. Some page opening, closing and sliding event callbacks during the drag process:

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

2. Start creating a ViewDragHelper instance, still created when the custom View DragLayout is initialized, using the static method of ViewGragHelper:

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

When the create() method was created, a dragHelperCallBack callback class was passed in, which will be discussed in the fourth point.

3. Then you need to rewrite the event method in ViewGroup, intercept the touch event and process it internally in ViewGragHelper, so as to achieve the purpose of dragging and moving the sub-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; 
}
Copy after login

Here we Intercept in onInterceptTouchEvent to transfer the event from the parent control to the child View, and then intercept in the onTouchEvent method to let ViewDragHelper perform consumption processing.

4. Start customizing the creation of the instance dragHelperCallback of ViewDragHelper.Callback to implement an abstract method tryCaptureView and rewrite the following methods to implement the side-sliding function. Let’s take a look at them one by one.

/** 
* 拦截所有的子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; 
}
Copy after login

It is time to intercept all sub-Views in the ViewGroup (in this case: DragLayout) and return true directly, indicating that all sub-Views can be dragged and moved.

/** 
* 水平方向移动 
* @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; 
} 
}
Copy after login

Implement this method to express horizontal sliding. At the same time, the boundary value will be judged in the method. For example, when the main view above has moved to the left outside the boundary, it will directly return 0, which means that it can only move to the left. x=0; then moving to the right will determine the distance to the right of the range. The initialization of the range will be discussed later. Except for these two situations, just return to left directly.

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

This method is necessary to implement because this method returns 0 by default inside the Callback. That is to say, if the click event of the view is true, then the entire sub-View will not be able to be dragged and moved. . Then the width of the left view is returned directly here, which represents the farthest distance of horizontal sliding.

/** 
* 当拖拽的子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(); 
} 
}
Copy after login

This method is called when the finger is released while dragging the sub-View. This will determine the intention of moving left or right and open or close the man view (upper view). The following is the last method implemented: 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); 
} 
};
Copy after login

This method is called back during the process of dragging and moving the sub-View, and then redefines the left view and main view according to the moving coordinate position. At the same time, the dispathDragEvent() method is called for drag event related processing and distribution, and the interface is called back according to the status:

/** 
* 进行处理拖拽事件 
* @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(); 
} 
}
Copy after login

There is a line of code in this method float percent=mainLeft/(float)range; it will be used after calculating a percentage. Go to

5. As for the initialization of the sub-View layout and the size setting method of width, height and horizontal sliding distance:

/** 
* 布局加载完成回调 
* 做一些初始化的操作 
*/
@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); 
}
Copy after login

and the callback method when the control size changes:

@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); 
}
Copy after login

In this method we can obtain the width, height and drag horizontal distance in real time.

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

Android uses ViewDragHelper to implement the latest version of QQ6.X side-sliding interface effect example code

然后根据前面算出来的百分比来缩放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)); 
} 
}
Copy after login

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

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

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>
Copy after login

该布局文件中父层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>
Copy after login

该布局还是比较简单的,对于上层主内容布局这边就放一个顶部导航栏和中的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(); 
} 
}); 
} 
}
Copy after login

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

Android uses ViewDragHelper to implement the latest version of QQ6.X side-sliding interface effect example code

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

4.正式运行效果如下:

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

Android uses ViewDragHelper to implement the latest version of QQ6.X side-sliding interface effect example code

(六).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); 
} 
} 
}
Copy after login

(七).最后总结

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

更多Android uses ViewDragHelper to implement the latest version of QQ6.X side-sliding interface effect example code相关文章请关注PHP中文网!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template