首頁  >  文章  >  Java  >  Android使用ViewDragHelper實作QQ6.X最新版本側滑介面效果實例程式碼

Android使用ViewDragHelper實作QQ6.X最新版本側滑介面效果實例程式碼

高洛峰
高洛峰原創
2017-01-13 10:29:561275瀏覽

(一).前言:

這兩天QQ進行了重大更新(6.X)尤其在UI風格上面由之前的藍色換成了白色居多了,側滑效果也發生了一些變化,那我們今天來模仿實現一個QQ6.X版本的側滑介面效果。今天我們還是採用神器ViewDragHelper來實現.

本次實例具體程式碼已經上傳到下面的專案中,歡迎各位去star和fork一下。

https://github.com/jiangqqlmj/DragHelper4QQ
FastDev4Android框架專案位址:https://github.com/jiangqqlmj/FastDev4Android

rag

(3338383對我們的基本使用我們的基本使用方法,同時也知道了裡邊的若干個方法的用途,下面我們還是把基本的使用步驟溫習一下。要使用ViewGragHelper實作子View拖曳移動的步驟如下:

建立ViewGragHelper實例(傳入Callback)


重寫事件攔截處理方法onInterceptTouch和onTouchEvent


實作Callback,實作中的相關方法或水平垂直方向移動的距離方法


更加具體分析大家可以看前一篇博客,或者我們今天這邊會透過具體實例講解一下。


(三).QQ5.X側滑效果實現分析:

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

Android使用ViewDragHelper實作QQ6.X最新版本側滑介面效果實例程式碼觀察上面我們可以理解為兩個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; 
}

這邊我們在onInterceptTouch攔截讓事件從父控制往子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的缩放效果,所以我们这边引入了一个动画开源库:

Android使用ViewDragHelper實作QQ6.X最新版本側滑介面效果實例程式碼

然后根据前面算出来的百分比来缩放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中作如下配置:

Android使用ViewDragHelper實作QQ6.X最新版本側滑介面效果實例程式碼

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

4.正式运行效果如下:

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

Android使用ViewDragHelper實作QQ6.X最新版本側滑介面效果實例程式碼

(六).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的运用,具体该知识点的使用方法,我已经在我的博客中更新讲解的文章,欢迎大家查看。

更多Android使用ViewDragHelper實作QQ6.X最新版本側滑介面效果實例程式碼相关文章请关注PHP中文网!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn