安卓開發之ViewDragHelper的使用及自定義可下拉展示內容的ViewGroup
一、ViewDragHelper
一個自定義ViewGroup的工具類,它提供了許多有用的方法和狀態允許使用者去拖拽和繪製子View在自定義ViewGroup中的軌跡和位置。
ViewDragHelper可以使用靜態方法建立一個例項:
ViewDragHelper.create(ViewGroup forParent,int sensitiveity,ViewDragHelper.Callback cb)
在自定義ViewGroup中,ViewDragHelper可以幫助我們來分析手勢和處理拖動:
@Override public boolean onTouchEvent(MotionEvent event) { try { //處理觸控事件 mDragHelper.processTouchEvent(event); } catch (Exception e) { e.printStackTrace(); } //返回true, return true; }
使用ViewDragHelper來動態移動自定義ViewGroup中的控制元件:
public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop) // Animate the view child to the given (left, top) position. // 返回true 代表還沒有移動到指定的位置,需要重新整理介面,繼續移動 // 返回false 就停止工作
使用ViewDragHelper滑動邊緣監聽:
// 監聽左邊緣滑動 setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
二、 ViewDragHelper.Callback
ViewDragHelper.Callback整合了許多可覆寫的方法,所有移動的控制在ViewDragHelper.Callback裡面來實現。
是否可以捕捉ViewGroup中的子元件:
public boolean tryCaptureView(View child, int pointerId) { //返回true,就代表著可對該子元件處理滑動事件。否則就不會處理。 return true; //只對特定的元件捕捉 return speChild == child; }
// 使用ViewDragHelper的captureChildView捕捉子元件,該方法可以繞過tryCaptureView方法
clampViewPositionHorizontal[Vertical]:
處理子元件在水平或者豎直方向的滑動限制,在這個方法內部做子元件的邊界處理,就是確保子元件不會滑過界。
例如在豎直方向進行滑動時,一般先獲取控制元件可滑動到的頂端Y值和底端Y值,再進行一個取值
@Override public int clampViewPositionVertical(View child, int top, int dy) { //手指觸控移動時實時回撥, top表示要到的y位置 int topBound = ...; int bottomBound = ...; return Math.min(Math.max(topBound, top), bottomBound); }
onViewPositionChanged
當前拖動的子元件位置變化時呼叫的方法。一般在該方法裡調整其他子元件的位置。@Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { //changedView為當前位置發生改變的View,left,top分別為該View的left和top座標 }
onViewReleased
當手指釋放的時候會呼叫的方法。在這個方法裡實現鬆開時的滑動效果。
@Override public void onViewReleased(View releasedChild, float xvel, float yvel) { //released 為釋放的View,xvel,yvel分別為該手指離開時滑動和豎直滑動的速度 }
getViewVertical[Horizontal]DragRangeHorizontal
@Override public int getViewVerticalDragRange(View child) { //返回當前捕捉的child子元件的豎直滑動範圍 return ...; }
onEdgeDragStarted(int edgeFlags, int pointerId)
// 邊緣滑動時回撥 @Override public void onEdgeDragStarted(int edgeFlags, int pointerId) { // edgeFlags為邊緣滑動的方法標誌 }
……
三、ViewDragHelper的使用
自定義可下拉展示內容的的ViewGroup
效果圖:
一、自定義ViewGroup:DragDownLayout
可支援padding和子元件寬高的wrap_content
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
/**
* Created by cxm on 2016/8/22.
*/
public class DragDownLayout extends ViewGroup {
private ViewDragHelper dragHelper;
private View mDragbar, mContentView;
private int dragRange;
private OnOpenListener mOnOpenListener;
private OnCloseListener mOnCloseListener;
private boolean isOpen;//是否開啟著
public DragDownLayout(Context context) {
super(context);
init();
}
public DragDownLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DragDownLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public DragDownLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
dragHelper = ViewDragHelper.create(this, mCallback);
}
@Override
protected void onLayout(boolean b, int l, int t, int r, int bo) {
mDragbar.layout(getPaddingLeft(), getPaddingTop(), getWidth()-getPaddingRight(), mDragbar.getMeasuredHeight()+getPaddingTop());
mContentView.layout(getPaddingLeft(), getPaddingTop()-mContentView.getMeasuredHeight(), getWidth()-getPaddingRight(), getPaddingTop());
}
@Override
public boolean onInterceptHoverEvent(MotionEvent event) {
final int action = MotionEventCompat.getActionMasked(event);
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
dragHelper.cancel();
return false;
}
return dragHelper.shouldInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
dragHelper.processTouchEvent(event);
return true;
}
private ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child == mDragbar;
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
// top為mDragbar的top值
mContentView.layout(getPaddingLeft(), top-mContentView.getHeight(), getWidth()-getPaddingRight(), top );
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
int topBound = getPaddingTop();//頂端邊界
int bottomBound = getHeight() - mDragbar.getHeight()-getPaddingBottom();//底端邊界
return Math.min(Math.max(topBound, top), bottomBound);
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
// 禁止水平滑動
return getPaddingLeft();
}
@Override
public int getViewVerticalDragRange(View child) {
dragRange = mContentView.getMeasuredHeight();
return dragRange;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if (mContentView.getBottom() - getPaddingTop() > mContentView.getHeight() / 2) {
smoothToBottom();
} else if (mContentView.getBottom() - getPaddingTop() <= mContentView.getHeight() / 2) {
smoothToTop();
}
invalidate();
}
};
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mDragbar = getChildAt(0);
mContentView = getChildAt(1);
measureChild(mDragbar,widthMeasureSpec,heightMeasureSpec);
int dragBarHeight = mDragbar.getMeasuredHeight();
measureChild(mContentView,widthMeasureSpec,heightMeasureSpec);
int contentHeight = mContentView.getMeasuredHeight();
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), dragBarHeight+contentHeight+getPaddingBottom()+getPaddingTop());
}
private void smoothToTop() {
if (dragHelper.smoothSlideViewTo(mDragbar, getPaddingLeft(), getPaddingTop())) {
ViewCompat.postInvalidateOnAnimation(this);
isOpen = false;
if(mOnCloseListener!=null) mOnCloseListener.close();
}
}
private void smoothToBottom() {
if (dragHelper.smoothSlideViewTo(mDragbar, getPaddingLeft(), getHeight()-getPaddingBottom()-mDragbar.getHeight())) {
ViewCompat.postInvalidateOnAnimation(this);
isOpen = true;
if(mOnOpenListener!=null) mOnOpenListener.open();
}
}
@Override
public void computeScroll() {
super.computeScroll();
if (dragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
public boolean isOpen(){
return isOpen;
}
public void openContent(){
if(!isOpen) smoothToBottom();
}
public void closeContent(){
if(isOpen) smoothToTop();
}
public interface OnOpenListener{
void open();
}
public interface OnCloseListener{
void close();
}
public void setOnOpenListener(OnOpenListener mOnOpenListener) {
this.mOnOpenListener = mOnOpenListener;
}
public void setOnCloseListener(OnCloseListener mOnCloseListener) {
this.mOnCloseListener = mOnCloseListener;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (getChildCount() != 2) {
throw new IllegalStateException("Just contain two Views/ViewGroups ");
}
}
}
二、在xml佈局檔案中使用DragDownLayout
支援DragDownLayout的padding,沒有支援子View的margin。
拖拽控制元件和內容控制元件的高度可wrap_content / 具體值,寬度需為match_parent。
<com.cxmscb.cxm.dtest.DragDownLayout
android:id="@+id/myDragDownLayout"
android:background="#e0ffff"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:background="#e000ff"
android:layout_width="match_parent"
android:layout_height="56dp"
android:text="歡迎"
android:textColor="#ffffff"
android:gravity="center_vertical"
android:paddingLeft="15dp"
android:textSize="19sp" />
<TextView
android:id="@+id/content"
android:background="#e000ff"
android:layout_width="match_parent"
android:layout_height="150dp"
android:text="Content"
android:gravity="center"
android:textSize="20sp"/>
</com.cxmscb.cxm.dtest.DragDownLayout>
三、對DragDownLayout設定監聽
mDragDownLayout = (DragDownLayout) findViewById(R.id.myDragDownLayout);
mDragDownLayout.setOnOpenListener(new DragDownLayout.OnOpenListener() {
@Override
public void open() {
Toast.makeText(MainActivity.this,"open",Toast.LENGTH_SHORT).show();
}
});
Github:DragDownLayout
相關文章
- Android ViewDragHelper 自定義 ViewGroup 神器AndroidView
- Android ViewDragHelper完全解析 自定義ViewGroup神器AndroidView
- .Net微信網頁開發之使用微信JS-SDK自定義微信分享內容網頁JS
- 快速開發偷懶必備,搞定所有ViewGroup的Adapter . 支援自定義ViewGroupViewAPT
- Android開發教程:自定義ViewGroup方法總結AndroidView
- BeetleX之webapi自定義響應內容WebAPI
- iOS 自定義內容的彈窗iOS
- 打造可顯示上傳內容的自定義進度條
- wordpress 自定義路由及展示頁路由
- react封裝一個可自定義內容的modal彈框元件React封裝元件
- 自定義shell提示內容
- android自定義View&自定義ViewGroup(下)AndroidView
- android自定義View&自定義ViewGroup(上)AndroidView
- Smartisan OS一步之自定義拖拽內容
- PHP開發之自定義函式及陣列PHP函式陣列
- 2.15 自定義表單文字框內容的格式 [iOS開發中的神兵利器]iOS
- Android自定義ViewGroup(一)AndroidView
- Android自定義控制元件之自定義ViewGroup實現標籤雲Android控制元件View
- ViewGroup篇:玩一下自定義ViewGroupView
- Android動畫效果之自定義ViewGroup新增布局動畫Android動畫View
- 安卓自定義的AlertDialog的一些使用安卓
- 安卓開發之Volley的基本使用安卓
- android短視訊開發,自定義下拉選單Android
- Android自定義View:ViewGroup(三)AndroidView
- 自定義viewgroup(6)--使用adapter適配資料ViewAPT
- 自定義viewgroup(5)--可滾動佈局,GestureDetector手勢監聽View
- DRF內建許可權元件之自定義許可權管理類元件
- 在vue裡,下載自定義內容的檔案Vue
- WPF 自定義控制元件的坑(蠢的:自定義控制元件內容不顯示)控制元件
- 安卓開發之Fragment的使用與通訊安卓Fragment
- 【安卓筆記】下拉重新整理元件的使用及實現安卓筆記元件
- RSS 解析:全球內容分發的利器及使用技巧
- 自定義UILabel內容顯示內邊距UI
- 自定義 Passport token 失效後返回內容Passport
- Android開發之自定義SpinnerAndroid
- Dcat Admin 自定義 Form 表單實現後臺系統配置內容的自定義,並可擴充套件配置項。ORM套件
- 自定義流式佈局:ViewGroup的測量與佈局View
- 自定義ViewGroup,實現Android的側滑選單ViewAndroid