日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自定义控件:侧滑面板

發布時間:2025/4/16 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自定义控件:侧滑面板 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本篇博客講解的是自定義View之側滑面板,應用場景:QQ,知乎,效果圖如下

1. 內容摘要

  • 了解ViewDragHelper 的產生及解決的問題
  • 掌握ViewDragHelper 的使用步驟
  • 掌握屬性動畫的使用
  • 掌握狀態更新及事件回調的用法

2. 實現最簡單的拖拽

2.1 實現最簡單的拖拽

在創建DragLayout 時,繼承FrameLayout,這里需要注意兩個問題

為什么不繼承ViewGroup,因為繼承ViewGroup 需要重寫onMeasure()和實現onLayout()方法,自己實現子view 的測量和擺放,在這里我們不需要自己去做測量和擺放,而FrameLayout 已經對這兩個方法進行了具體實現,所以繼承FrameLayout 更加簡單省事

為什么不繼承RelativeLayout,因為這里我們只需要層級關系,不需要相對關系,繼承RelativeLayout界面效果是一樣的,但RelativeLayout 對FrameLayout 多了相對關系的計算,效率會低一些,所以選擇繼承FrameLayout

public class DragLayout extends FrameLayout {public DragLayout(Context context) {super(context);}public DragLayout(Context context, AttributeSet attrs) {super(context, attrs);}public DragLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}}

2.2 串聯構造方法

DragLayout 實例化時需要做一些初始化操作,如果我們定義一個init()方法,則我們需要在三個構造方法中都調用init()方法,這樣非常麻煩,我們可以通過串連三個構造方法的方式實現只調用一次init()方法這樣無論是代碼創建還是布局在xml 中都能調用到我們的初始化代碼

public class DragLayout extends FrameLayout {public DragLayout(Context context) {//代碼創建時調用this(context, null);}public DragLayout(Context context, AttributeSet attrs) {//布局在xml 中,實例化時調用this(context, attrs, 0);}public DragLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);//在這里初始化}}

2.3 ViewDragHelper 簡介

我們要實現拖拽的效果,則需要自己去解析Touch 事件的ACTION_DOWN,ACTION_MOVE,ACTION_UP,相當的麻煩。所以Google 在2013 年的IO 大會上發布了ViewDragHelper 這個類,用來解決滑動拖拽問題,用這個類可以非常簡單的實現view 的拖拽

2.4 創建ViewDragHelper

由于eclipse 創建項目時,為我們添加的android-support-v4.jar 沒有包含ViewDragHelper,我們需要將最新的android-support-v4.jar 拷貝到libs 下面,然后clean 一下工程。

在這里我們需要關聯android-support-v4.jar 的源碼,通過配置文件的方法來關聯源碼

在libs 下面創建一個android-support-v4.jar.properties 的文件

android-support-v4.jar.properties 中的內容為src = V4 包源碼路徑

我們只需要在第三個構造方法中實現ViewDragHelper 的實例即可

public DragLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// 在這里初始化// forParent 父類容器// sensitivity 敏感度,越大越敏感,1.0f 是默認值// Callback 回調事件//1.通靜態方法創建拖拽輔助類mViewDragHelper = ViewDragHelper.create(this, 1.0f, mCallback);}

ViewDragHelper 三個參數的創建的方法源碼中的mTouchSlop 表示觸摸的最小敏感范圍,越小越敏感即在界面拖動的瞬間變化量大于mTouchSlop 時才可以成功觸發拖拽事件

public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb){final ViewDragHelper helper = create(forParent, cb);helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity));return helper;}

2.5 觸摸事件轉交

ViewDragHelper 創建成功了,但它和DragLayout 并沒有任何關系,我們需要讓它們建立關系

//2.轉交觸摸事件@Overridepublic boolean onInterceptTouchEvent(MotionEvent event) {//由ViewDragHelper 判斷是否攔截return mViewDragHelper.shouldInterceptTouchEvent(event);};

重寫onInterceptTouchEvent 方法,將觸摸事件交給ViewDragHelper 判斷是否攔截,這樣它們就建立了關系,事件攔截后,還需要對攔截到的事件進行處理,注意返回值必須是true

@Overridepublic boolean onTouchEvent(MotionEvent event) {try {//由ViewDragHelper 處理攔截的事件mViewDragHelper.processTouchEvent(event);} catch (Exception e) {}//事件已被處理,所以需要返回truereturn true;};

2.6 處理回調事件

ViewDragHelper 在處理觸摸事件時會通過傳入的callback 給我們反饋,通過對回調方法的處理即可實現簡單的拖拽

//3.處理回調事件ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {@Override//返回值決定了child 是否可以被拖拽public boolean tryCaptureView(View child, int pointerId) {//child 被用戶拖拽的孩子//pointerId 多點觸摸的手指idreturn true;}@Override//修正子view 水平方向上的位置,此時還沒有真正的移動,返回值決定view 將移動到的位置public int clampViewPositionHorizontal(View child, int left, int dx) {//left 建議移動到的位置return left;}};

2.7 DragLayout 布局到xml 中

給左面板和主面板設置不同的背景顏色便于拖拽時觀察效果,運行工程,即可實現簡單的拖拽

<com.example.draglayout.widget.DragLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/bg"><LinearLayout android:layout_width="match_parent"android:layout_height="match_parent"android:background="#66ff0000"></LinearLayout><LinearLayout android:layout_width="match_parent"android:layout_height="match_parent"android:background="#00ff00"></LinearLayout></com.example.draglayout.widget.DragLayout>

3. 限定拖拽范圍

現在左面板和主面板可以任意拖動,本節要實現左面板不動,拖動時,主面板在一定范圍內拖動

3.1 OnFinishInflate()介紹

onFinishInflate()在控件inflate 完成時會被調用,可以在這個方法中查找子控件

  • 可以通過findViewById()的方式查找子控件
  • 可以通過子view 索引的方式查找子控件

這里采用第二種方式

@Overrideprotected void onFinishInflate() {super.onFinishInflate();//增強代碼的健壯性if(getChildCount() < 2){//必須有兩個子viewthrow new IllegalStateException("Your viewgroup must have two children.");}if(!(getChildAt(0)instanceofViewGroup)||!(getChildAt(1)instanceof ViewGroup)){//子view 必須是viewgroup 的子類throw new IllegalStateException("The child must an instance of viewgroup.");}mLeftContent = getChildAt(0);mMainContent = getChildAt(1);};

3.2 獲取控件寬高

在onMeasure()方法中可以獲取到控件的寬高,也可以在onSizeChanged()方法中去獲取寬高,onMeasure()方法調用后會檢測寬高值有沒有變化,有變化才調用onSizeChanged()方法,無變化則不調用,所以onSizeChanged()調用的次數比onMeasure()少,在這里我們在onSizeChanged()方法中去獲取寬高,同時計算出拖拽范圍為寬度的60%

@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mWidth = getMeasuredWidth();mHeight = getMeasuredHeight();//拖拽的范圍mRange = (int) (mWidth * 0.6f);System.out.println("mWidth:"+mWidth+" mHeight:"+mHeight +" mRange:"+mRange);}

3.3 限定主面板的拖動范圍

對callback 中的其它幾個方法進行重寫

//3.處理回調事件ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {@Override//返回值決定了child 是否可以被拖拽public boolean tryCaptureView(View child, int pointerId) {//child 被用戶拖拽的孩子//pointerId 多點觸摸的手指idreturn true;}@Overridepublic int getViewHorizontalDragRange(View child) {return super.getViewHorizontalDragRange(child);}@Override//修正子view 水平方向上的位置,此時還沒有真正的移動,返回值決定view 將移動到的位置public int clampViewPositionHorizontal(View child, int left, int dx) {//left 建議移動到位置return left;}@Overridepublic void onViewPositionChanged(View changedView, int left, int top,int dx, int dy) {super.onViewPositionChanged(changedView, left, top, dx, dy);}@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {super.onViewReleased(releasedChild, xvel, yvel);}};

回調方法中的getViewHorizontalDragRange(View child)方法返回拖拽的范圍,但不會真正限定這個范圍,只要返回一個大于零的值即可。

在ViewDragHelper 源碼中,computeSettleDuration()會調用這個返回值來計算動畫執行的時長,checkTouchSlop()方法會調用這個返回值檢查左面板,主面板是否可以被滑動,所以需要返回一個大于0的值才能實現拖動。

如果返回值為0,左面板,主面板中不能有子view 或子view 沒有對touch 事件做處理,最后觸摸還是會交給ViewDragHelper 處理,所以也能實現拖動

@Override//返回拖拽的范圍,返回一個大于零的值,計算動畫執行的時長,水平方向是否可以被滑開public int getViewVerticalDragRange(View child) {//computeSettleDuration 計算動畫執行的時長//checkTouchSlop 檢查是否可以被滑動(沒有孩子處理觸摸事件,最后返回給DragLayout 處理)return mRange;}

限定主面板的拖拽范圍,當建議的值left 小于0 時,讓left 等于0,大于mRange 時等于mRange,然后再將left 返回

@Override// 修正子view 水平方向上的位置,此時還沒有真正的移動,返回值決定view 將移動到的位置public int clampViewPositionHorizontal(View child, int left, int dx) {// child 被用戶拖拽的孩子// left 建議移動到位置// dx 新的位置與舊的位置的差值int oldLeft = mMainContent.getLeft();System.out.println("clamp: left:" + left + " oldLeft:" + oldLeft+ " dx:" + dx);if (child == mMainContent) {left = fixLeft(left);}return left;}/*** 修正左邊的位置,限定拖拽范圍在0 到mRange 間變化** @param left* @return*/private int fixLeft(int left) {if (left < 0) {left = 0;} else if (left > mRange) {left = mRange;}return left;}

當控件位置變化時會調用onViewPositionChanged()方法,可以在此方法中做伴隨動畫,狀態更新,事件回調,left 表示最新的水平位置,dx 表示剛剛發生的水平變化量。

此時左面板還可以任意拖動,為了實現拖動左面板時界面表現為拖動主面板,可以對changedView 進行判斷,如果changedView 是左面板,則通過layout()把左面板放回到原來的位置,然后把變化量dx 累加給主面板,再通過layout()方法來移動主面板

@Override// 當控件位置變化時調用,可以做伴隨動畫,狀態更新,事件回調public void onViewPositionChanged(View changedView, int left, int top,int dx, int dy) {super.onViewPositionChanged(changedView, left, top, dx, dy);// left 最新的水平位置// dx 剛剛發生的水平變化量System.out.println("onViewPositionChanged: left:" + left + " dx:"+ dx);if (changedView == mLeftContent) {// 如果滑動的是左面板// 1.放回到原來的位置mLeftContent.layout(0, 0, mWidth, mHeight);// 2.把變化量傳遞給主面板,主面板舊的值+變化量int newLeft = mMainContent.getLeft() + dx;// 需要修正左邊值newLeft = fixLeft(newLeft);mMainContent.layout(newLeft, 0, newLeft + mWidth, mHeight);}// offsetLeftAndRight 在低版本中沒有重繪界面,手動調用重繪invalidate();}

注意:由于onViewPositionChanged()方法調用前調用了offsetLeftAndRight()方法,此方法在低版本中沒有重繪界面,并且在高版本中也有一個bug,最后一幀沒有被繪制,所以需要手動調用一次invalidate(),否則在低版本中無法實現拖拽效果

4. 結束動畫

拖拽過程中當手指抬起時,需要實現一個打開,關閉面板的動畫,結束動畫可以在 onViewReleased()方法實現

4.1 跳轉的結束動畫

onViewReleased()方法在松手之后會被調用,此時可以做結束動畫,結束動畫只需要考慮需要打開的
情況,其它則為需要關閉情況

  • 當水平方向的速度等于 0,并且主面板此時左邊的位置在拖拽范圍中軸線的右邊則需要執行打開動

畫,即 mMainContent.getLeft() > mRange*0.5f

  • 當水平方向的速度大于 0 時,則需要執行打開動畫
  • 其它情況則需要執行關閉動畫
//5.決定松手后要做的事件,結束動畫public void onViewReleased(View releasedChild, float xvel, float yvel) {super.onViewReleased(releasedChild, xvel, yvel);//releasedChild 被釋放的孩子//xvel 水平方向的速度,向左為-,向右為+System.out.println("onViewReleased: xvel:"+xvel);//考慮開啟的情況,其它情況則關閉的情況if(xvel == 0 && mMainContent.getLeft()> mRange*0.5f){//在允許滑動的范圍的中軸線右邊,則打開open();}else if(xvel > 0){//速度向右時,則打開open();}else{//關閉close();}}

open(),close()創建為 DragLayout 的方法,這樣方便外界調用

//直接打開protected void open() {mMainContent.layout(mRange, 0, mRange + mWidth, mHeight);}//直接關閉protected void close() {mMainContent.layout(0, 0, 0 + mWidth, mHeight);}

4.2 平滑的結束動畫

首先實現平滑的打開動畫,在這里需要用到 ViewDragHelper 提供的一個方法smoothSlideViewTo(child,finalLeft,finalTop),三個參數的意思分別是:

  • child 需要平滑移動的 view
  • finalLeft 需要移動到的終點左邊位置
  • finalTop 需要移動到的終點的上邊位置

smoothSlideViewTo()方法的返回值為 true,表示位置不是最終位置,需要重繪界面

重載一個 open(boolean isSmooth)方法,用參數 isSmooth 標識是調用平滑動畫還是跳轉動畫,open()方法則直接調用 open(true),默認為平滑動畫

protected void open() {open(true);}protected void open(boolean isSmooth) {int finalLeft = mRange;if(isSmooth){//觸發一個平滑動畫if(mViewDragHelper.smoothSlideViewTo(mMainContent, finalLeft, 0)){//invalidate();可能會漏幀ViewCompat.postInvalidateOnAnimation(this);};}else{//直接跳轉mMainContent.layout(finalLeft, 0, finalLeft + mWidth, mHeight);}}

注意:smoothSlideViewTo()方法返回 true,需要重繪界面,此時不建議使用 invalidate(),因為在動畫的過程中可能會丟幀,推薦使用 ViewCompat.postInvalidateOnAnimation(this),參數一定要傳子 view 所在的容器,因為只有容器才知道子 view 的具體位置

重繪命令調用后,還需要重寫 computScroll()方法,重繪時,系統會在 draw()方法后調用 computScroll(),在該方法中調用 ViewDragHelper 的維持動畫的方法
continueSettling(deferCallbacks)參數 deferCallbacks 表示是否延遲畫下一幀,此處傳入 true,返回值表示是否已經移動到最終位置,如果為 true,還沒有移動到最終位置,需要重繪界面,這樣 computeScroll()方法就會不斷的調用,界面也就會不斷的重繪,直到移動到最終位置

@Override//維持動畫的執行,高頻率調用public void computeScroll() {super.computeScroll();//調用完后會調用 draw()if(mViewDragHelper.continueSettling(true)){//參數傳入 true,表示延遲畫下一幀//mViewDragHelper.continueSettling(true)ViewCompat.postInvalidateOnAnimation(this);}}

同樣的道理,關閉的平滑動畫只需要修改 finalLeft = 0 即可

protected void close() {close(true);}protected void close(boolean isSmooth) {int finalLeft = 0;if(isSmooth){//觸發一個平滑動畫if(mViewDragHelper.smoothSlideViewTo(mMainContent, finalLeft, 0)){//invalidate();可能會漏幀ViewCompat.postInvalidateOnAnimation(this);};}else{mMainContent.layout(finalLeft, 0, finalLeft + mWidth, mHeight);}}

5. 伴隨動畫

5.1 分解伴隨動畫

伴隨動畫是拖拽的過程中,左面板,主面板會跟隨拖拽百分比所做的動畫,該動畫需要在onViewPositionChanged()回調方法中實現

  • 左面板:縮放動畫,平移動畫,透明度動畫
  • 主面板:縮放動畫
  • 背景: 亮度變化

5.2 實現伴隨動畫

創建一個方法 dispatchDragEvent(),在 onViewPositionChanged()方法中調用

public void onViewPositionChanged(View changedView, int left, int top,int dx, int dy) {super.onViewPositionChanged(changedView, left, top, dx, dy);//...此處代碼省略dispatchDragEvent();invalidate();}

實現左面板的縮放動畫

protected void dispatchDragEvent() {//0.0f->1.0f 獲取動畫的百分比,主面板左邊的位置引起的一系列變化float percent = mMainContent.getLeft()*1.0f/mRange;System.out.println("dispatchDragEvent: percent:"+percent);//左面板:縮放動畫,平移動畫,透明度動畫//0.0f ->1.0f percent*0.5f => 0.0f -> 0.5f//尋找規律->拷貝 FloatEvaluator.java 中的估值方法//percent*0.5f + 0.5f => 0.5f -> 1.0f//percent*(1.0f -0.6f)+0.6f => 0.6f -> 1.0f => start + percent(end - start)//兼容低版本引入 nineoldandroid.jar//用 ViewHelper 做屬性動畫//1.縮放動畫ViewHelper.setScaleX(mLeftContent, evaluate(percent, 0.5f, 1.0f));ViewHelper.setScaleY(mLeftContent, evaluate(percent, 0.5f, 1.0f));}//源碼 FloatEvaluator.java 中拷貝的估值方法public Float evaluate(float fraction, Number startValue, Number endValue) {float startFloat = startValue.floatValue();return startFloat + fraction * (endValue.floatValue() - startFloat);}
  • 第 3 行通過主面板左邊位置與拖拽范圍的相除可以得到一個 0.0f ->1.0f 的比例值,因為在整個拖拽過
    程中,主面板左邊位置的變化是引起一系列變化的原因
  • 第 7-10 行可以推出一個公式 start + percent(end - start),即通過 percent 的變化可以計算出 start 到 end 間
    的任意值。源碼 FloatEvaluator.java 中已經提供了這么一個方法,將其拷貝到代碼中,即第 20-23 行
  • 第 12-16 行為了兼容低版本引入 nineoldandroid.jar 中的 ViewHelper 做屬性動畫

同理可以實現其它伴隨動畫

protected void dispatchDragEvent() {//0.0f->1.0f 獲取動畫的百分比,主面板左邊的位置引起的一系列變化float percent = mMainContent.getLeft()*1.0f/mRange;System.out.println("dispatchDragEvent: percent:"+percent);//左面板:縮放動畫,平移動畫,透明度動畫//0.0f ->1.0f percent*0.5f => 0.0f -> 0.5f//尋找規律->拷貝 FloatEvaluator.java 中的估值方法//percent*0.5f + 0.5f => 0.5f -> 1.0f//percent*(1.0f -0.6f)+0.6f => 0.6f -> 1.0f => start + percent(end - start)//兼容低版本引入 nineoldandroid.jar//用 ViewHelper 做屬性動畫//1.縮放動畫,從 50%->100%ViewHelper.setScaleX(mLeftContent, evaluate(percent, 0.5f, 1.0f));ViewHelper.setScaleY(mLeftContent, evaluate(percent, 0.5f, 1.0f));//2.平移動畫,從寬度一半在屏幕外->全部移到屏幕內ViewHelper.setTranslationX(mLeftContent, evaluate(percent, -mWidth*0.5f, 0f));//3.透明度動畫,從 20%->100%ViewHelper.setAlpha(mLeftContent, evaluate(percent, 0.2f, 1.0f));//主面板:縮放動畫,從 100%->80%ViewHelper.setScaleY(mMainContent, evaluate(percent, 1.0f, 0.8f));//背景亮度變化,PorterDuff.Mode.SRC_OVER 疊加模式,直接疊加在上面getBackground().setColorFilter((Integer)evaluateColor(percent, Color.BLACK,Color.TRANSPARENT), PorterDuff.Mode.SRC_OVER);}//源碼 ArgbEvaluator.java 中拷貝的估值方法public Object evaluateColor(float fraction, Object startValue, Object endValue) {//api18 以上的代碼才有透明度的過濾int startInt = (Integer) startValue;int startA = (startInt >> 24) & 0xff;int startR = (startInt >> 16) & 0xff;int startG = (startInt >> 8) & 0xff;int startB = startInt & 0xff;int endInt = (Integer) endValue;int endA = (endInt >> 24) & 0xff;int endR = (endInt >> 16) & 0xff;int endG = (endInt >> 8) & 0xff;int endB = endInt & 0xff;return (int)((startA + (int)(fraction * (endA - startA))) << 24) |(int)((startR + (int)(fraction * (endR - startR))) << 16) |(int)((startG + (int)(fraction * (endG - startG))) << 8) |(int)((startB + (int)(fraction * (endB - startB))));}
  • 第 27 行疊加模式 PorterDuff.Mode.SRC_OVER 表示直接疊加在上面
  • 第 30-48 行 ArgbEvaluator.java 源碼中拷貝的估值方法,api18 以上的代碼才有透明度的過濾

6. 狀態更新及事件回調

6.1 狀態分析

拖拽的狀態可以分為:

  • 打開狀態
  • 關閉狀態
  • 拖拽狀態

通過枚舉定義這三種狀態,且定義默認狀態為關閉

//默認狀態為關閉private Status status = Status.Close;//提供 get()方法public Status getStatus() {return status;}//狀態的枚舉值,有三種狀態,打開,關閉,拖拽中public enum Status{Open,Close,Draging;}

6.2 事件回調分析

定義一個事件回調接口,事件回調和狀態密切相關

  • 打開狀態時回調 onOpen()方法
  • 關閉狀態時回調 onClose()方法

拖拽中回調 onDraging(float percent)方法,并將拖拽百分比傳出去

//接收外界注冊的接口類,以便回調接口方法private OnDragChangeListener onDragChangeListener;//提供 set()方法,讓外界注冊監聽接口類public void setOnDragChangeListener(OnDragChangeListener onDragChangeListener) {this.onDragChangeListener = onDragChangeListener;}//模仿 View 的 OnClickListener 的寫法,定義一個內部的公開的接口public interface OnDragChangeListener{/*** 打開時調用*/public void onOpen();/*** 關閉時調用*/public void onClose();/*** 拖拽中調用* @param percent 當前拖拽的百分比*/public void onDraging(float percent);}

6.3 實現狀態更新及事件回調

通過拖拽百分比可以判斷當前的狀態,在 dispatchDragEvent()方法中實現狀態更新及事件回調

  • 百分比為 0,則為關閉狀態
  • 百分比為 1,則為打開狀態
  • 其它百分比,則為拖拽狀態

事件回調需要先做空判斷,拖拽狀態調用頻率高,直接調用即可,打開和關閉可以判斷上次狀態和當
前狀態是否一致,不一致則調用

protected void dispatchDragEvent() {//0.0f->1.0f 獲取動畫的百分比,主面板左邊的位置引起的一系列變化float percent = mMainContent.getLeft()*1.0f/mRange;System.out.println("dispatchDragEvent: percent:"+percent);Status lastStatus = status;//更新狀態,通過動畫百分比判斷if(percent ==0 ){status = Status.Close;}else if(percent == 1){status = Status.Open;}else{status = Status.Close;}if(onDragChangeListener != null){//調用頻率高,直接調用onDragChangeListener.onDraging(percent);}if(lastStatus != status && onDragChangeListener != null){if(status == Status.Open){//最新狀態是 open,說明剛才不是 open,則需要調用一下 onOpen 方法onDragChangeListener.onOpen();}else if(status == Status.Close){//最新狀態是 close,說明剛才不是 close,則需要調用一下 onClose 方法onDragChangeListener.onClose();}}//左面板:縮放動畫,平移動畫,透明度動畫//0.0f ->1.0f percent*0.5f => 0.0f -> 0.5f//尋找規律->拷貝 FloatEvaluator.java 中的估值方法//percent*0.5f + 0.5f => 0.5f -> 1.0f//percent*(1.0f -0.6f)+0.6f => 0.6f -> 1.0f => start + percent(end - start)//兼容低版本引入 nineoldandroid.jar//用 ViewHelper 做屬性動畫//1.縮放動畫ViewHelper.setScaleX(mLeftContent, evaluate(percent, 0.5f, 1.0f));ViewHelper.setScaleY(mLeftContent, evaluate(percent, 0.5f, 1.0f));//2.平移動畫ViewHelper.setTranslationX(mLeftContent, evaluate(percent, -mWidth*0.5f, 0f));//3.透明度動畫ViewHelper.setAlpha(mLeftContent, evaluate(percent, 0.2f, 1.0f));//主面板:縮放動畫ViewHelper.setScaleY(mMainContent, evaluate(percent, 1.0f, 0.8f));//背景亮度變化,如果沒有設置背景會出問題,PorterDuff.Mode.SRC_OVER 疊加模式,直接疊加在上面getBackground().setColorFilter((Integer)evaluateColor(percent, Color.BLACK,Color.TRANSPARENT), PorterDuff.Mode.SRC_OVER);}

7. 觸摸優化

7.1 填充界面數據

1.修改主界面 xml,左面板,主面板分別加入 ListView 及頭像

<com.example.draglayout.widget.DragLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/dl"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/bg"tools:context=".MainActivity" ><LinearLayout android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="50dp"android:paddingLeft="10dp"android:paddingRight="50dp"android:orientation="vertical"android:paddingTop="50dp" ><ImageView android:layout_width="50dp"android:layout_height="50dp"android:contentDescription="@null"android:src="@drawable/head" /><ListView android:id="@+id/lv_left"android:layout_width="match_parent"android:layout_height="match_parent" ></ListView></LinearLayout><com.example.draglayout.widget.MyLinearLayout android:id="@+id/ll_my"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#ffffff"android:orientation="vertical" ><RelativeLayout android:layout_width="match_parent"android:layout_height="50dip"android:background="#18b6ef"android:gravity="center_vertical" ><ImageView android:id="@+id/iv_header"android:layout_width="30dp"android:layout_height="30dp"android:layout_marginLeft="10dp"android:contentDescription="@null"android:src="@drawable/head" /></RelativeLayout><ListView android:id="@+id/lv_main"android:layout_width="match_parent"android:layout_height="match_parent" ></ListView></com.example.draglayout.widget.MyLinearLayout></com.example.draglayout.widget.DragLayout>

2.ListView 數據源

public class Cheeses {public static final String[] sCheeseStrings = {"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi","Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale","Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue","Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"};public static final String[] NAMES = new String[]{"宋江", "盧俊義", "吳用","公孫勝", "關勝", "林沖", "秦明", "呼延灼", "花榮", "柴進", "李應", "朱仝", "魯智 深","武松", "董平", "張清", "楊志", "徐寧", "索超", "戴宗", "劉唐", "李逵", "史進", " 穆弘","雷橫", "李俊", "阮小二", "張橫", "阮小五", " 張順", "阮小七", "楊雄", "石秀", " 解珍"," 解寶", "燕青", "朱武", "黃信", "孫立", "宣贊", "郝思文", "韓滔", "彭玘", "單廷珪 ","魏定國", "蕭讓", "裴宣", "歐鵬", "鄧飛", " 燕順", "楊林", "凌振", "蔣敬", "呂方 ","郭 盛", "安道全", "皇甫端", "王英", "扈三娘", "鮑旭", "樊瑞", "孔明", "孔亮", " 項充","李袞", "金大堅", "馬麟", "童威", "童猛", "孟康", "侯健", "陳達", "楊春", "鄭天壽 ","陶宗旺", "宋清", "樂和", "龔旺", "丁得孫", "穆春", "曹正", "宋萬", "杜遷", "薛永 ", " 施恩","周通", "李忠", "杜興", "湯隆", "鄒淵", "鄒潤", "朱富", "朱貴", "蔡福", "蔡慶", " 李立","李云", "焦挺", "石勇", "孫新", "顧大嫂", "張青", "孫二娘", " 王定六", "郁保四", " 白勝","時遷", "段景柱"};} public class DragLayout extends FrameLayout {private static final String TAG = "TAG";private View mLeftContent;private View mMainContent;private View mRightContent;private int mWidth;private int mHeight;private int mRangeLeft;private ViewDragHelper mDragHelper;private Status mStatus = Status.Close;private Direction mDirction = Direction.Left;private OnDragListener mDragListener;private boolean mScaleEnable = true;private int mRightWidth;private int mRangeRight;public interface OnDragListener {void onClose();void onStartOpen(Direction direction);void onOpen();void onDrag(float percent);}public static enum Status {Open, Close, Draging}public static enum Direction {Left, Right, Default}public Direction getDirction() {return mDirction;}public void setDirction(Direction dirction) {mDirction = dirction;}public DragLayout(Context context) {this(context, null);}public DragLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public DragLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);mDragHelper = ViewDragHelper.create(this, mCallBack);mGestureDetector = new GestureDetectorCompat(context, mYGestureListener);}SimpleOnGestureListener mYGestureListener = new SimpleOnGestureListener() {public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {return Math.abs(distanceX) >= Math.abs(distanceY);};};@Overrideprotected void onFinishInflate() {Log.i(TAG, "--onFinishInflate");mLeftContent = (View) getChildAt(0);mRightContent = getChildAt(1);mMainContent = (View) getChildAt(2);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);Log.i(TAG, "--onSizeChanged");mWidth = mMainContent.getMeasuredWidth();mHeight = mMainContent.getMeasuredHeight();mRightWidth = mRightContent.getMeasuredWidth();mRangeLeft = (int) (mWidth * 0.6f);mRangeRight = mRightWidth;}private int mMainLeft = 0;ViewDragHelper.Callback mCallBack = new ViewDragHelper.Callback() {@Overridepublic boolean tryCaptureView(View child, int pointerId) {// 1. 決定當前被拖拽的child是否拖的動。(抽象方法,必須重寫)Log.d(TAG, "tryCaptureView: " + (child == mMainContent) + " : "+ (child == mLeftContent) + " : "+ (child == mRightContent));return true;}@Overridepublic int getViewHorizontalDragRange(View child) {// 2. 決定拖拽的范圍return mWidth;}@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) {// 3. 決定拖動時的位置,可在這里進行位置修正。(若想在此方向拖動,必須重寫,因為默認返回0)Log.d(TAG, "clampViewPositionHorizontal left: " + left + " dx: "+ dx + " mRange: " + mRangeLeft);return clampResult(mMainLeft + dx, left);}@Overridepublic void onViewPositionChanged(View changedView, int left, int top,int dx, int dy) {// 4. 決定了當View被拖動時,希望同時引發的其他變化Log.d(TAG, "onViewPositionChanged left: " + left + " dx: " + dx);if (changedView == mMainContent) {mMainLeft = left;} else {mMainLeft += dx;}mMainLeft = clampResult(mMainLeft, mMainLeft);if(changedView == mLeftContent || changedView == mRightContent){layoutContent();}dispathDragEvent(mMainLeft);invalidate();};/*** @param releasedChild* 被釋放的孩子* @param xvel* 釋放時X方向的速度* @param yvel* 釋放時Y方向的速度*/@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {// 5. 決定當childView被釋放時,希望做的事情——執行打開/關閉動畫,更新狀態boolean scrollRight = xvel > 1.0f;boolean scrollLeft = xvel < -1.0f;if (scrollRight || scrollLeft) {if (scrollRight && mDirction == Direction.Left) {open(true, mDirction);} else if (scrollLeft && mDirction == Direction.Right) {open(true, mDirction);} else {close(true);}return;}if (releasedChild == mLeftContent && mMainLeft > mRangeLeft * 0.7f) {open(true, mDirction);} else if (releasedChild == mMainContent) {if (mMainLeft > mRangeLeft * 0.3f)open(true, mDirction);else if (-mMainLeft > mRangeRight * 0.3f)open(true, mDirction);elseclose(true);} else if (releasedChild == mRightContent&& -mMainLeft > mRangeRight * 0.7f) {open(true, mDirction);} else {close(true);}}@Overridepublic void onViewDragStateChanged(int state) {if (mStatus == Status.Close && state == ViewDragHelper.STATE_IDLE&& mDirction == Direction.Right) {mDirction = Direction.Left;}}@Overridepublic void onViewCaptured(View capturedChild, int activePointerId) {};};private int clampResult(int tempValue, int defaultValue) {Integer minLeft = null;Integer maxLeft = null;if (mDirction == Direction.Left) {minLeft = 0;maxLeft = 0 + mRangeLeft;} else if (mDirction == Direction.Right) {minLeft = 0 - mRangeRight;maxLeft = 0;}if (minLeft != null && tempValue < minLeft)return minLeft;else if (maxLeft != null && tempValue > maxLeft)return maxLeft;elsereturn defaultValue;}private GestureDetectorCompat mGestureDetector;@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);Log.i(TAG, "--onMeasure");}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {Log.i(TAG, "--onLayout");layoutContent();}private void layoutContent() {mLeftContent.layout(0, 0, mWidth, mHeight);mRightContent.layout(mWidth - mRightWidth, 0, mWidth, mHeight);mMainContent.layout(mMainLeft, 0, mMainLeft + mWidth, mHeight);}@Overridepublic void computeScroll() {if (mDragHelper.continueSettling(true)) {ViewCompat.postInvalidateOnAnimation(this);}}public void setDragListener(OnDragListener mDragListener) {this.mDragListener = mDragListener;}/*** 處理其他同步動畫* * @param mainLeft*/protected void dispathDragEvent(int mainLeft) {// 注意轉換成floatfloat percent = 0;if (mDirction == Direction.Left)percent = mainLeft / (float) mRangeLeft;else if (mDirction == Direction.Right)percent = Math.abs(mainLeft) / (float) mRangeRight;if (mDragListener != null) {mDragListener.onDrag(percent);}// 更新動畫if (mScaleEnable) {animViews(percent);}// 更新狀態Status lastStatus = mStatus;if (updateStatus() != lastStatus) {if(lastStatus == Status.Close && mStatus == Status.Draging){mLeftContent.setVisibility(mDirction == Direction.Left ? View.VISIBLE : View.GONE);mRightContent.setVisibility(mDirction == Direction.Right ? View.VISIBLE : View.GONE);if(mDragListener != null){mDragListener.onStartOpen(mDirction);}}if (mStatus == Status.Close) {if (mDragListener != null)mDragListener.onClose();} else if (mStatus == Status.Open) {if (mDragListener != null)mDragListener.onOpen();}}}private Status updateStatus() {if (mDirction == Direction.Left) {if (mMainLeft == 0) {mStatus = Status.Close;} else if (mMainLeft == mRangeLeft) {mStatus = Status.Open;} else {mStatus = Status.Draging;}} else if (mDirction == Direction.Right) {if (mMainLeft == 0) {mStatus = Status.Close;} else if (mMainLeft == 0 - mRangeRight) {mStatus = Status.Open;} else {mStatus = Status.Draging;}}return mStatus;}private void animViews(float percent) {Log.d(TAG, "percent: " + percent);animMainView(percent);animBackView(percent);}private void animBackView(float percent) {if (mDirction == Direction.Right) {// 右邊欄X, Y放大,向左移動, 逐漸顯示ViewHelper.setScaleX(mRightContent, 0.5f + 0.5f * percent);ViewHelper.setScaleY(mRightContent, 0.5f + 0.5f * percent);ViewHelper.setTranslationX(mRightContent,evaluate(percent, mRightWidth + mRightWidth / 2.0f, 0.0f));ViewHelper.setAlpha(mRightContent, percent);} else {// 左邊欄X, Y放大,向右移動, 逐漸顯示ViewHelper.setScaleX(mLeftContent, 0.5f + 0.5f * percent);ViewHelper.setScaleY(mLeftContent, 0.5f + 0.5f * percent);ViewHelper.setTranslationX(mLeftContent,evaluate(percent, -mWidth / 2f, 0.0f));ViewHelper.setAlpha(mLeftContent, percent);}// 背景逐漸變亮getBackground().setColorFilter(caculateValue(percent, Color.BLACK, Color.TRANSPARENT),PorterDuff.Mode.SRC_OVER);}private void animMainView(float percent) {Float inverseP = null;if (mDirction == Direction.Left) {inverseP = 1 - percent * 0.25f;} else if (mDirction == Direction.Right) {inverseP = 1 - percent * 0.25f;}// 主界面X,Y縮小if (inverseP != null) {if (mDirction == Direction.Right) {ViewHelper.setPivotX(mMainContent, mWidth);ViewHelper.setPivotY(mMainContent, mHeight / 2.0f);} else {ViewHelper.setPivotX(mMainContent, mWidth / 2.0f);ViewHelper.setPivotY(mMainContent, mHeight / 2.0f);}ViewHelper.setScaleX(mMainContent, inverseP);ViewHelper.setScaleY(mMainContent, inverseP);}}public Float evaluate(float fraction, Number startValue, Number endValue) {float startFloat = startValue.floatValue();return startFloat + fraction * (endValue.floatValue() - startFloat);}private int caculateValue(float fraction, Object start, Object end) {int startInt = (Integer) start;int startIntA = startInt >> 24 & 0xff;int startIntR = startInt >> 16 & 0xff;int startIntG = startInt >> 8 & 0xff;int startIntB = startInt & 0xff;int endInt = (Integer) end;int endIntA = endInt >> 24 & 0xff;int endIntR = endInt >> 16 & 0xff;int endIntG = endInt >> 8 & 0xff;int endIntB = endInt & 0xff;return ((int) (startIntA + (endIntA - startIntA) * fraction)) << 24| ((int) (startIntR + (endIntR - startIntR) * fraction)) << 16| ((int) (startIntG + (endIntG - startIntG) * fraction)) << 8| ((int) (startIntB + (endIntB - startIntB) * fraction));}float mDownX;private SwipeListAdapter adapter;@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {if(getStatus() == Status.Close){int actionMasked = MotionEventCompat.getActionMasked(ev);switch (actionMasked) {case MotionEvent.ACTION_DOWN:mDownX = ev.getRawX();break;case MotionEvent.ACTION_MOVE:if(adapter.getUnClosedCount() > 0){return false;}float delta = ev.getRawX() - mDownX;if(delta < 0){return false;}break;default:mDownX = 0;break;}}return mDragHelper.shouldInterceptTouchEvent(ev)& mGestureDetector.onTouchEvent(ev);}public void close(){close(true);}public void close(boolean withAnim) {mMainLeft = 0;if (withAnim) {if (mDragHelper.smoothSlideViewTo(mMainContent, mMainLeft, 0)) {ViewCompat.postInvalidateOnAnimation(this);}} else {layoutContent();dispathDragEvent(mMainLeft);}}public void open(){open(true);}public void open(boolean withAnim) {open(withAnim, Direction.Left);}public void open(boolean withAnim, Direction d) {mDirction = d;if (mDirction == Direction.Left)mMainLeft = mRangeLeft;else if (mDirction == Direction.Right)mMainLeft = -mRangeRight;if (withAnim) {// 引發動畫的開始if (mDragHelper.smoothSlideViewTo(mMainContent, mMainLeft, 0)) {// 需要在computeScroll中使用continueSettling方法才能將動畫繼續下去(因為ViewDragHelper使用了scroller)。ViewCompat.postInvalidateOnAnimation(this);}} else {layoutContent();dispathDragEvent(mMainLeft);}}@Overridepublic boolean onTouchEvent(MotionEvent event) {try {mDragHelper.processTouchEvent(event);} catch (Exception e) {e.printStackTrace();}return true;}public Status getStatus() {return mStatus;}public void switchScaleEnable() {this.mScaleEnable = !mScaleEnable;if (!mScaleEnable) {animBackView(1.0f);}}public void setAdapterInterface(SwipeListAdapter adapter) {this.adapter = adapter;}} public class DragRelativeLayout extends RelativeLayout {private DragLayout dl;public DragRelativeLayout(Context context) {super(context);}public DragRelativeLayout(Context context, AttributeSet attrs) {super(context, attrs);}public DragRelativeLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public void setDragLayout(DragLayout dl) {this.dl = dl;}@Overridepublic boolean onInterceptTouchEvent(MotionEvent event) {if (dl.getStatus() != Status.Close) {return true;}return super.onInterceptTouchEvent(event);}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (dl.getStatus() != Status.Close) {if (event.getAction() == MotionEvent.ACTION_UP) {dl.close(true);}return true;}return super.onTouchEvent(event);} }

代碼:https://github.com/JackChen1999/DragLayout

總結

以上是生活随笔為你收集整理的自定义控件:侧滑面板的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

日韩黄色大片在线观看 | 91av大全 | 日韩欧美精品一区 | 亚洲视频免费在线 | 免费三级在线 | 西西44人体做爰大胆视频 | 麻豆国产露脸在线观看 | 欧美日韩不卡一区二区 | 99在线国产 | 日韩专区在线观看 | 欧美一区二区三区四区夜夜大片 | 久久精品五月 | 欧美日韩3p | 欧洲在线免费视频 | 97人人看| 亚洲精品免费观看视频 | www.狠狠操| 久草在线资源网 | 日日夜夜91 | 91新人在线观看 | 日韩精品中文字幕在线观看 | 国内精品视频一区二区三区八戒 | 日韩电影中文字幕 | 中文字幕国产在线 | 国产中文欧美日韩在线 | 日韩电影黄色 | 亚洲人人爱 | 免费久久99精品国产 | av片子在线观看 | 人人玩人人添人人 | 天天色天天草天天射 | 97在线免费观看 | 色婷婷亚洲精品 | 免费在线观看成年人视频 | 午夜久久精品 | 久久精品www人人爽人人 | 久久免费的精品国产v∧ | 久久不见久久见免费影院 | 久久人人97超碰com | 在线成人短视频 | 日本精品免费看 | 99视频在线 | 国产精品99久久久 | 视色网站 | 手机成人免费视频 | 久久久久久免费视频 | 久草在线视频网 | 69xx视频 | 天天爽天天爽 | 亚洲国产精品视频 | 国产999精品久久久久久绿帽 | 国产中文在线播放 | 国产91精品一区二区麻豆网站 | 国产精品久久久久av福利动漫 | 免费亚洲黄色 | 国产一区高清在线观看 | 成全免费观看视频 | 一本色道久久精品 | 最新国产在线视频 | 国产精品久久久久久久免费大片 | 国产精品免费久久久久久 | 五月婷婷六月丁香 | 999久久久免费精品国产 | 色偷偷网站视频 | 91看片淫黄大片91 | 久草视频免费播放 | 日本女人在线观看 | 99免费在线观看 | 久久美女免费视频 | 九九免费在线视频 | 亚洲精品九九 | 蜜桃视频色 | 国产午夜在线观看 | 97在线免费观看视频 | 久久国产欧美日韩 | 亚洲精品视频网站在线观看 | 欧美日韩不卡在线 | 操操爽 | 精品国产区 | 欧美激情视频一区 | 黄色日视频 | 久久免费大片 | 久久99免费 | www.天天成人国产电影 | 人人草人人草 | 久久精品韩国 | 欧美在线视频一区二区 | 在线观看成人小视频 | 九九欧美视频 | 人人爽人人爽人人爽学生一级 | 久久99久久久久久 | 最近中文字幕完整视频高清1 | 国产精品女同一区二区三区久久夜 | www.成人sex | 在线免费性生活片 | 成 人 a v天堂 | 九色91在线 | 伊人婷婷在线 | 亚欧洲精品视频在线观看 | 天天干人人插 | 91精品视频导航 | 亚洲国产精品影院 | 日日碰狠狠躁久久躁综合网 | 国产亚洲精品久久网站 | 日韩精品一区二区电影 | 国产精品久久久免费 | aⅴ视频在线 | 91精品久久久久久久久久入口 | 亚洲高清视频在线观看免费 | 天天摸夜夜添 | 日韩一级电影网站 | 久久夜色精品国产欧美一区麻豆 | 九九九电影免费看 | 国产99在线播放 | 婷婷视频导航 | 嫩草av在线 | 欧美一级片 | 国产高清视频色在线www | 日韩欧美专区 | 四川bbb搡bbb爽爽视频 | 免费看一级特黄a大片 | 超碰97在线资源 | 国产中文字幕在线免费观看 | 欧美 日韩 性 | 成人资源站 | 日韩国产精品一区 | 成人免费色 | 国产精品免费久久久久久 | 91亚洲网| 毛片3| 亚洲精品视频在线观看免费 | 摸bbb搡bbb搡bbbb| japanesexxxhd奶水| 成年人在线视频观看 | 国产精品区一区 | 日韩网站在线免费观看 | 日韩精品久久久久久中文字幕8 | 欧美日韩国产在线一区 | 欧美日本三级 | 国产明星视频三级a三级点| 国产精品婷婷午夜在线观看 | 麻豆传媒一区二区 | 日本精品在线看 | 亚洲精品一区二区18漫画 | 国产96在线观看 | 天天色 天天 | 色六月婷婷 | 狠狠色噜噜狠狠狠狠2022 | 亚洲激情在线视频 | 激情久久久久 | 韩国av一区二区三区 | 色综合小说| 久久99免费| 中文字幕av播放 | 国产尤物在线视频 | 色婷婷六月天 | 亚洲一二区视频 | 色综合久久久久久久久五月 | 色综合激情久久 | 国产一线二线三线在线观看 | 97在线影院 | 久久黄色成人 | 久久久久久久国产精品 | 国产中文字幕网 | 色婷婷88av视频一二三区 | 一区二区三区四区影院 | 黄色av网站在线免费观看 | 韩国精品视频在线观看 | 97超碰资源站 | 国产 一区二区三区 在线 | 91av片 | 国产一区二区在线精品 | 色综合久久中文字幕综合网 | 美女亚洲精品 | 色婷婷综合久久久久中文字幕1 | 色婷婷 亚洲 | 国产亚洲精品bv在线观看 | 国产高清免费av | 久久人人添人人爽添人人88v | 91福利视频久久久久 | 国产成人av一区二区三区在线观看 | 亚洲激情小视频 | 久久成人国产精品 | 色视频网页 | 精品女同一区二区三区在线观看 | 久久久久女人精品毛片九一 | 欧美精品日韩 | 欧美性久久久久久 | 91重口视频| 天天摸天天舔天天操 | 91九色国产| 久久国产视屏 | 在线播放av网址 | 成人app在线免费观看 | 国产黄色片在线 | 国产热re99久久6国产精品 | 国产亚洲欧美在线视频 | 啪啪肉肉污av国网站 | 久久人人爽人人爽人人片av软件 | 久久99国产精品自在自在app | 美女网色| 中文字幕丝袜美腿 | 欧美性生活免费看 | 婷婷六月在线 | 精品久久久久免费极品大片 | 麻豆成人小视频 | 天堂av最新网址 | 国产高清日韩 | 国产精品专区在线观看 | 久久久久成人精品免费播放动漫 | av福利资源 | 亚洲精品国产精品国 | 91视频高清| 在线观看91网站 | 精品久久久久久久 | 91精品免费在线观看 | 久久8精品 | 色综合夜色一区 | 久久久久久久久电影 | 国产精品久久久一区二区三区网站 | 成人av亚洲 | 91九色porny蝌蚪视频 | 中国精品少妇 | 国产成人av | 在线视频电影 | 国产v在线播放 | 西西www4444大胆视频 | 久久久久久欧美二区电影网 | 久久久久久国产精品久久 | 久草在线免费资源站 | 午夜免费在线观看 | 黄色免费视频在线观看 | 国产精品a久久 | 色多视频在线观看 | 一区二区三区影院 | 亚洲黄网址 | 黄色a一级片 | 视频在线观看一区 | 91高清视频| 国产精品一区二区久久久 | 亚洲一级久久 | 最近中文字幕国语免费av | 亚洲精品一区二区18漫画 | 国产午夜精品一区 | 日韩成年视频 | 中日韩免费视频 | 九九爱免费视频 | 久久久久久久久电影 | 成人免费电影 | 午夜骚影 | 激情综合五月网 | 亚洲综合激情 | 久久丝袜视频 | 中文字幕av一区二区三区四区 | 三级黄色欧美 | 综合五月| 夜夜夜草 | 国产精品区二区三区日本 | 在线观看网站你懂的 | 国产精品乱码一区二三区 | 最新一区二区三区 | 久久五月婷婷丁香 | 午夜精品麻豆 | 黄色小说视频在线 | 美腿丝袜一区二区三区 | 久久夜色精品亚洲噜噜国4 午夜视频在线观看欧美 | 午夜精品久久久久久中宇69 | 国产中文字幕视频在线 | 亚洲国产合集 | 亚洲国产精品一区二区久久hs | 韩国av一区二区三区 | 久久免费视频一区 | 五月婷婷影院 | 色婷婷激情 | 日本99久久 | 国产手机在线播放 | 99视频在线 | 天天草综合网 | 81国产精品久久久久久久久久 | 高潮毛片无遮挡高清免费 | 97热视频 | 三上悠亚在线免费 | 又黄又爽又刺激视频 | 日躁夜躁狠狠躁2001 | 伊人宗合| 人人舔人人插 | 夜夜操网 | 免费人成在线观看 | 久久精品亚洲精品国产欧美 | 中文字幕在线有码 | 国产精品嫩草影院99网站 | 99精品毛片 | 天天搞天天干 | 国产精品第72页 | 国产99久久99热这里精品5 | 一区视频在线 | 国产视频综合在线 | 18国产精品白浆在线观看免费 | 国产小视频在线免费观看视频 | 国产精品网址在线观看 | 久久99精品国产91久久来源 | 亚洲综合情 | 成人影片在线播放 | 在线中文字母电影观看 | 天天在线操 | www.色五月 | 7777xxxx| 久久这里只有精品视频首页 | 在线看日韩av| 综合久久久 | 在线看黄色的网站 | 国产天天综合 | 亚洲人成网站精品片在线观看 | 91精品国产高清自在线观看 | 亚洲第一区精品 | 久久久免费观看 | 亚洲性视频 | 狠狠久久 | 成人一级| 中文字幕专区高清在线观看 | 在线日韩精品视频 | 国产成人精品不卡 | 欧美激情精品久久久久久免费 | 一区二区三区播放 | 国产一区免费在线 | 日韩视频一区二区在线 | 一级黄色免费网站 | 丁香婷婷激情国产高清秒播 | 成人久久综合 | 国模吧一区 | 欧美国产日韩一区二区三区 | 久久国产精品99久久久久久老狼 | 一二三区av | 国产精品成人av电影 | 亚洲一区天堂 | 国产精品久久久精品 | www.啪啪.com | 久久五月婷婷丁香 | 日韩精品在线免费播放 | 成人播放器 | 久久婷婷网 | 亚洲人成人99网站 | 97视频播放| 欧美9999| 国产视频一区在线免费观看 | 午夜少妇一区二区三区 | 日韩中字在线 | 丁香花在线观看视频在线 | 午夜视频一区二区三区 | 欧美精品三级 | 久久久久久黄色 | 99久久久| 国产日韩av在线 | 麻豆视频免费在线观看 | 四虎影视精品成人 | 人人爱人人爽 | 国产精品99久久久久久久久久久久 | 欧美人牲| 97在线看| 国产精品美女视频 | 成人免费看电影 | 久草在线一免费新视频 | 亚洲一区二区视频 | 亚洲我射av | 日韩精品电影在线播放 | 中文字幕在线视频网站 | 黄色app网站在线观看 | 久久久久一区二区三区四区 | 日韩不卡高清 | 江苏妇搡bbbb搡bbbb | 激情av一区二区 | 91九色国产蝌蚪 | 精品一二三四在线 | 天天操天天操天天操天天操天天操天天操 | 欧美日韩国产综合一区二区 | 国产一区成人在线 | 亚洲色五月 | 国产手机视频在线观看 | 97超碰人人看 | 97视频免费播放 | 精品毛片一区二区免费看 | 欧美尹人 | 2023年中文无字幕文字 | 免费在线观看成人小视频 | 精品久久中文 | 国产一级特黄电影 | 中文字幕av在线免费 | 日韩啪啪小视频 | 青青草国产成人99久久 | 国产精品欧美久久久久久 | 久久免费黄色大片 | 精品国产伦一区二区三区观看说明 | 日韩高清精品免费观看 | 欧美大片mv免费 | 一本一道久久a久久精品蜜桃 | 国产拍在线 | 500部大龄熟乱视频 欧美日本三级 | 欧美精品小视频 | 最新极品jizzhd欧美 | 欧美日韩国产高清视频 | www.狠狠色.com| 波多野结衣电影一区二区三区 | 麻豆一二 | 精品一区二区在线观看 | 五月婷婷狠狠 | 久久精品一区八戒影视 | 成人综合免费 | 中文av免费| 91视频麻豆视频 | 又长又大又黑又粗欧美 | 999成人国产 | 国产精品欧美一区二区 | 亚洲精品xxxx | 在线观看视频97 | 97超碰中文字幕 | 99久久日韩精品免费热麻豆美女 | 99视频在线观看视频 | 91精品日韩 | 欧美日一级片 | av 一区 二区 久久 | 日韩欧美在线观看 | 黄色特一级 | 69国产精品视频免费观看 | 久久精品xxx | 欧美天天干 | 波多野结衣视频一区二区 | 日韩视频免费观看高清 | 91av色| 欧美精彩视频在线观看 | 亚洲国产成人av网 | 欧美成人手机版 | 免费视频资源 | 国产精品igao视频网入口 | 黄色国产高清 | 国产福利91精品一区 | 最近字幕在线观看第一季 | 国产一区二区中文字幕 | 五月婷婷在线观看视频 | av久久在线| 国产婷婷 | 丁香午夜| 国产精品国产三级国产不产一地 | 成人午夜电影免费在线观看 | 久久精品1区 | 97色狠狠 | 91麻豆精品国产午夜天堂 | 亚洲国产视频在线 | 在线观看视频在线 | 亚洲精品国产精品国自产观看 | 欧美午夜a| 深夜国产在线 | 中文字幕中文字幕在线一区 | 亚洲天堂网在线播放 | 国产成人精品综合久久久久99 | 日韩天天操 | 亚洲精品在线视频播放 | 麻花豆传媒一二三产区 | 国产中文字幕在线观看 | 国产精品欧美日韩 | 四虎国产精品免费 | 日韩高清免费在线观看 | 国产电影黄色av | 精品国产区在线 | 国产96在线 | 国产精品99久久久久久有的能看 | 天天操夜夜叫 | 国产成人亚洲在线观看 | 国产91勾搭技师精品 | 亚洲欧洲精品一区二区精品久久久 | 天天弄天天干 | 国产成人99久久亚洲综合精品 | 在线看国产一区 | 最新av在线播放 | 欧美电影黄色 | 碰天天操天天 | 亚洲国产精品成人精品 | 成人网大片| 日韩动漫免费观看高清完整版在线观看 | 久久香蕉影视 | 国产一区二区免费看 | 国产不卡精品 | 黄污视频网站 | 亚洲精品资源 | 天天色天天操天天爽 | 香蕉久久国产 | 500部大龄熟乱视频 欧美日本三级 | 五月婷婷在线观看视频 | 亚洲国产成人精品久久 | 丁香色综合 | 中文字幕一区二区三区视频 | 国产精品一区二区av影院萌芽 | 色九色 | 日韩欧美精品一区 | 天天操综| 麻豆久久 | 亚洲在线视频免费 | 国产亚洲精品久久久久久移动网络 | japanesefreesexvideo高潮| 黄网站免费看 | 国产九九九九九 | 一级性av | 91久久久久久久一区二区 | 综合天天久久 | 久久精品视频99 | 婷婷在线精品视频 | 国产精品久久久久久久久久久久久 | 成年性视频 | 久久久免费精品 | 97精产国品一二三产区在线 | 99久久婷婷国产综合亚洲 | av免费线看| 91av在线免费播放 | 国语麻豆 | 这里只有精品视频在线观看 | 狠狠做深爱婷婷综合一区 | 波多野结衣在线播放一区 | 久草资源在线 | 国产精品一区二区久久精品 | 久久av观看 | 久久精品久久久精品美女 | 天天干,天天草 | 日本久久影视 | 欧美黑人巨大xxxxx | 在线www色| www,黄视频 | 欧美日韩亚洲第一 | 日韩欧美中文 | 免费成人结看片 | 在线影视 一区 二区 三区 | 久久久久久久久久久综合 | 久久五月婷婷综合 | 91网站观看 | 人人干人人草 | 91成人在线免费观看 | 国产剧情一区二区在线观看 | 亚洲午夜精品一区 | 在线免费国产视频 | 天天摸日日摸人人看 | 中文字幕亚洲欧美 | 日韩在线免费观看视频 | 国产中文字幕视频在线观看 | 欧美天堂视频在线 | 婷婷激情5月天 | 超碰公开在线 | 国内精品久久久久影院一蜜桃 | 国产精品永久免费 | 成年人av在线播放 | 五月综合 | 人人插人人舔 | 精品a视频 | 精品99999 | 91精品福利在线 | 欧美日韩观看 | 午夜精品福利在线 | 91毛片在线 | 97在线观看免费 | 日韩高清在线看 | 人人爽人人爽人人爽 | 中文字幕一区二区三区四区视频 | 亚洲经典视频在线观看 | 天天操夜夜爱 | av综合在线观看 | 狠狠狠操 | 在线亚洲午夜片av大片 | 日韩一区在线播放 | 日日摸日日添夜夜爽97 | 91色吧 | 国产一区久久久 | a极黄色片 | 免费av看片 | 免费高清在线视频一区· | 欧美色888| 国产精品久久99 | 国产精品综合在线 | 天天射天天做 | 国产精品久久免费看 | 中文免费 | 免费看的黄色网 | 一区中文字幕在线观看 | 日本 在线 视频 中文 有码 | 日本黄色片一区二区 | 91免费版在线观看 | 毛片基地黄久久久久久天堂 | 手机看片福利 | 波多野结衣久久精品 | 中文字幕在线日亚洲9 | 亚洲 欧美 国产 va在线影院 | 日本三级不卡视频 | av丝袜在线 | 九色精品免费永久在线 | 久久嗨 | www免费黄色| 国产色婷婷精品综合在线手机播放 | 国产精品不卡视频 | 亚洲一区久久久 | 欧美久久久久久久久久久 | 六月色 | 99成人免费视频 | 麻花天美星空视频 | 国产日本在线 | 99精品在线视频播放 | 亚洲国产中文字幕在线 | 亚洲精品国精品久久99热 | 激情导航 | 日韩精品专区在线影院重磅 | 91看片一区二区三区 | 久久1区 | 亚洲精品乱码久久久久久写真 | 亚洲日本韩国一区二区 | 色a网 | 日韩二区在线播放 | 国产精品福利久久久 | 色在线视频网 | 国产护士在线 | 国产精品永久 | 69xxxx欧美 | 911精品美国片911久久久 | 狠狠色噜噜狠狠狠狠 | 免费日韩 精品中文字幕视频在线 | 夜夜操天天干, | 欧美日韩综合在线观看 | 五月天狠狠操 | 日本精品一区二区 | 免费观看国产精品 | 国产成人精品一区一区一区 | 久久久久影视 | 国产精品久久久久四虎 | 日韩成人免费电影 | 在线观看91精品国产网站 | 欧美色精品天天在线观看视频 | 精品国产人成亚洲区 | 日韩中文字 | 六月婷婷网 | 精品国产一区二区在线 | 在线观看视频免费大全 | 亚洲狠狠婷婷综合久久久 | 色播激情五月 | 国模视频一区二区三区 | 又黄又刺激又爽的视频 | 色综合久久88色综合天天6 | 999视频在线播放 | 97在线精品视频 | 日韩字幕在线观看 | 五月婷在线播放 | 99热国产在线观看 | 综合久久网 | 国产午夜三级一二三区 | 久久黄视频 | 在线午夜电影神马影院 | 亚洲女人天堂成人av在线 | 国产美女精品视频免费观看 | 国产精品自产拍在线观看 | 色国产精品一区在线观看 | 国产精品99久久99久久久二8 | 丁香六月色 | 欧美一级性生活视频 | 天天曰夜夜爽 | 久久久免费 | 日韩成人黄色 | 五月婷婷视频在线 | 91黄视频在线观看 | 国产成人精品一二三区 | 日三级在线 | 国产乱码精品一区二区蜜臀 | 最近2019中文免费高清视频观看www99 | 97在线超碰 | 夜夜操网站 | 久久五月婷婷丁香社区 | 国内精品亚洲 | 综合精品在线 | 国产特级毛片aaaaaa高清 | 日韩在线理论 | 免费在线成人av电影 | 尤物九九久久国产精品的分类 | 国产又粗又长又硬免费视频 | 国产精品久久久久国产精品日日 | wwxxx日本| 国产精品毛片一区二区在线看 | 日韩欧美一区二区三区在线观看 | 九九热re| 精品国产乱子伦一区二区 | 免费国产一区二区视频 | 日韩中文字幕免费 | 国产一区网址 | 99久久99久久综合 | 超碰个人在线 | 在线天堂日本 | 日韩精品中文字幕久久臀 | 亚洲综合干 | 日韩美女免费线视频 | 美女网站视频一区 | 久久久影院一区二区三区 | 亚洲理论片在线观看 | 一级黄色大片 | 免费成人在线视频网站 | 日本中文在线观看 | 亚洲精品国产电影 | 欧美日韩不卡在线观看 | 月下香电影 | 成年人免费av网站 | 免费看三级黄色片 | 日韩av高清| 日韩精品黄 | 高清不卡免费视频 | 国产精品福利av | 国产视频久久久久 | 狠狠艹夜夜干 | 天天做天天爱天天综合网 | 国产精品18久久久久白浆 | 国产亚洲精品久久久久秋 | 激情伊人五月天久久综合 | 亚洲激情免费 | 国产精品第7页 | www最近高清中文国语在线观看 | 天天射天天拍 | 99视频在线看 | 色视频网站免费观看 | 69成人在线| 97视频播放 | av一本久道久久波多野结衣 | 久久涩视频 | 91视频亚洲| 国产成人精品av | 亚洲第一成网站 | 91看片一区二区三区 | 午夜精品久久久久久久久久久久久久 | 精品福利视频在线观看 | 久久午夜影视 | 中文字幕精 | 国产精品九色 | 国产精品福利在线观看 | 国产精品一区二区av日韩在线 | 国产无吗一区二区三区在线欢 | 免费在线观看一区二区三区 | 日韩av成人在线 | 亚洲六月丁香色婷婷综合久久 | 国产精品一区二区三区四区在线观看 | 国产黄色av| 国产夫妻性生活自拍 | 精品国产一区二区三区男人吃奶 | 丝袜美女视频网站 | 国产精品美女免费看 | 色橹橹欧美在线观看视频高清 | 日韩免费在线观看 | aaa免费毛片| 欧美乱熟臀69xxxxxx | 精品你懂的| 国产丝袜网站 | 91成人欧美| 激情综合色播五月 | 亚洲国产精品小视频 | 日日婷婷夜日日天干 | 69国产精品视频免费观看 | 啪啪免费视频网站 | 高清av免费观看 | 手机看片| 久久五月网 | 国产亚洲精品久久久久久久久久 | 国产精品剧情在线亚洲 | 四虎影视成人 | 亚洲精选视频在线 | 黄色午夜| 特级黄录像视频 | 亚洲精品国产精品国自产 | 手机在线小视频 | 免费看片黄色 | 超碰在线公开 | 久久久香蕉视频 | 天天久久综合 | 久久精品精品电影网 | 国产一级黄色片免费看 | 成人免费一区二区三区在线观看 | 九九热免费在线观看 | 国产手机在线精品 | av在线亚洲天堂 | 精品国产一二三四区 | 天天操天天射天天插 | 欧美最新另类人妖 | 中文在线免费观看 | 欧美在线你懂的 | 日日日日| 特级黄色一级 | 久久精品亚洲综合专区 | 人操人| 国产精品淫片 | 九九久久久 | 成人污视频在线观看 | 日韩区在线观看 | 亚洲国内精品在线 | 久久久影院官网 | 国产二级视频 | 久久九九久久九九 | 欧美激情视频一区二区三区免费 | 久久综合九色99 | 一区二区精品在线观看 | 亚洲精品国产成人av在线 | 中文字幕观看av | 久久精品一区二区三区国产主播 | 99色在线 | 91欧美精品 | 在线免费黄色av | 久久久久久久av | 三级免费黄 | 日韩免费在线观看视频 | 玖玖在线视频观看 | 成人网在线免费视频 | 国产正在播放 | 丁香花中文在线免费观看 | 精品久久久久久国产 | 麻豆极品 | 九九热中文字幕 | 亚洲精品电影在线 | 久久久高清一区二区三区 | 又色又爽又黄高潮的免费视频 | 国产 欧美 日韩 | 奇米影视四色8888 | 欧美日韩国产网站 | 日韩欧美91 | 99久久婷婷国产一区二区三区 | 91在线视频观看 | 在线91网| 婷婷.com| 中文字幕免费高清 | 国产精品中文字幕在线播放 | 国产精品1区2区3区在线观看 | 国产精品一区二区三区在线 | 国产在线欧美在线 | 中文区中文字幕免费看 | 97网站| 色视频成人在线观看免 | 夜色资源网 | 久草免费福利在线观看 | 粉嫩av一区二区三区四区五区 | 国产精品女主播一区二区三区 | 最新中文在线视频 | 精品久久久亚洲 | 亚洲综合成人av | 久久久免费视频播放 | 亚洲在线激情 | 欧美激情综合五月色丁香 | 国产午夜精品一区二区三区欧美 | 亚洲成a人片在线观看中文 中文字幕在线视频第一页 狠狠色丁香婷婷综合 | 久久99精品一区二区三区三区 | 激情欧美一区二区三区 | 一级一级一片免费 | 99久久99| 国产真实精品久久二三区 | 国产 欧美 在线 | 综合网婷婷| 欧美色精品天天在线观看视频 | 国产在线观看国语版免费 | 中文字幕乱码在线播放 | 久久久亚洲影院 | 亚洲春色综合另类校园电影 | 丁香色婷 | 欧美久久久久久久久久久久久 | 亚欧日韩av | 久草国产在线 | 人人干网站 | 成人精品国产免费网站 | 中文字幕在线观看av | 国产群p| 很黄很色很污的网站 | 国产一卡二卡在线 | 在线精品视频在线观看高清 | 欧美动漫一区二区三区 | 五月天久久精品 | 日韩一区二区三区视频在线 | 美女在线观看网站 | 99 色| 色哟哟国产精品 | 97综合在线| 狠狠狠狠狠狠狠狠干 | 91av片 | 国产精品成人av在线 | 成人黄性视频 | 久久久久久久久久网 | 在线播放精品一区二区三区 | 波多野结衣在线播放视频 | 国产成人精品一区二区三区免费 | 成人av资源在线 | av中文字幕在线免费观看 | 三级小视频在线观看 | 色婷婷激情五月 | 中文字幕乱码日本亚洲一区二区 | 亚洲一级黄色片 | 亚洲成年片| 国产高清在线看 | 91精品国产自产在线观看永久 | 午夜精品久久久久久久久久 | 91大神视频网站 | 久久99中文字幕 | 一区二区三区精品久久久 | av电影在线播放 | 久久激情视频免费观看 | 月下香电影 | 99se视频在线观看 | 91在线超碰 | 夜添久久精品亚洲国产精品 | 超碰在线观看av | 色网站国产精品 | 六月激情 | 九九九热精品免费视频观看网站 | 丁香视频全集免费观看 | 亚洲日韩欧美视频 | www激情网 | 日韩大片在线播放 | 免费日p视频 | 国产99一区视频免费 | 午夜在线免费视频 | 欧美精品在线一区 | 大型av综合网站 | 日韩理论片在线观看 | 91精品久久久久久综合乱菊 | 国产精品一区二区在线免费观看 | 日韩色一区二区三区 | 国产色综合天天综合网 | 国产在线观看,日本 | 中文字幕色站 | 亚洲永久免费av | 在线看av的网址 | 欧美a在线看 | 久久精品艹 | 3d黄动漫免费看 | 成人免费网站视频 | 国产丝袜制服在线 | 91香蕉嫩草 | 男女男视频 | 亚洲精品国久久99热 | 久久国产精品99久久久久久丝袜 | 在线观看国产www | 国产亚洲精品久 | 日本xxxx.com| 国产色黄网站 | 亚洲国产精品电影在线观看 | 久久99网站 | 在线观看片 | 麻豆视频在线免费观看 | 国产v亚洲v | 亚洲国产理论片 | 蜜臀aⅴ国产精品久久久国产 | 国产99久久| 亚洲视频一 | 色综合激情网 | 美女视频黄频大全免费 | 99re视频在线观看 | 一级成人免费视频 | 手机在线黄色网址 | 最近中文字幕免费av | 国产黑丝一区二区 | 欧美日韩免费观看一区=区三区 | 久久国产精品色av免费看 | 一区 二区电影免费在线观看 | 精品自拍sae8—视频 | 99热精品国产一区二区在线观看 | 免费av观看 | 日日爽日日操 | 国内精品久久久久影院男同志 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 草久视频在线 | 成人在线电影观看 | 日韩网站免费观看 | 亚洲精品视频网站在线观看 | 免费观看9x视频网站在线观看 | 最近高清中文字幕在线国语5 | 亚洲国产中文字幕在线视频综合 | av福利在线 | 国产精品免费视频一区二区 | 日日碰狠狠添天天爽超碰97久久 | 国产精品 视频 | 中午字幕在线观看 | 91看片淫黄大片一级在线观看 | 99精品久久久久 | 国产精品久久99综合免费观看尤物 | 色吊丝在线永久观看最新版本 | 色婷婷精品 | 国产精品久久久久久久久久久久 | 久久8精品| 中文在线免费一区三区 | 这里只有精品视频在线观看 | 开心激情五月婷婷 | 亚洲欧洲一区二区在线观看 | 亚洲天天综合 | 久久五月婷婷丁香 | 在线中文字幕播放 | 日韩中文字幕免费在线播放 | 伊人电影在线观看 | 久久精品观看 | 91高清免费 | 中文字幕一区二区三区乱码在线 | 天天人人综合 | 日本中文字幕久久 | 成人av资源网 | 久久99精品久久久久久清纯直播 | 亚洲视频久久久 | 国产精品区一区 | 狠狠干网址 | 综合成人在线 |