日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android视图状态及重绘流程分析,带你一步步深入了解View(三)

發布時間:2025/6/15 Android 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android视图状态及重绘流程分析,带你一步步深入了解View(三) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在前面一篇文章中,我帶著大家一起從源碼的層面上分析了視圖的繪制流程,了解了視圖繪制流程中onMeasure、onLayout、onDraw這三個最重要步驟的工作原理,那么今天我們將繼續對View進行深入探究,學習一下視圖狀態以及重繪方面的知識。如果你還沒有看過我前面一篇文章,可以先去閱讀 Android視圖繪制流程完全解析,帶你一步步深入了解View(二)?。

相信大家在平時使用View的時候都會發現它是有狀態的,比如說有一個按鈕,普通狀態下是一種效果,但是當手指按下的時候就會變成另外一種效果,這樣才會給人產生一種點擊了按鈕的感覺。當然了,這種效果相信幾乎所有的Android程序員都知道該如何實現,但是我們既然是深入了解View,那么自然也應該知道它背后的實現原理應該是什么樣的,今天就讓我們來一起探究一下吧。

一、視圖狀態

視圖狀態的種類非常多,一共有十幾種類型,不過多數情況下我們只會使用到其中的幾種,因此這里我們也就只去分析最常用的幾種視圖狀態。

1. enabled

表示當前視圖是否可用。可以調用setEnable()方法來改變視圖的可用狀態,傳入true表示可用,傳入false表示不可用。它們之間最大的區別在于,不可用的視圖是無法響應onTouch事件的。

2. focused

表示當前視圖是否獲得到焦點。通常情況下有兩種方法可以讓視圖獲得焦點,即通過鍵盤的上下左右鍵切換視圖,以及調用requestFocus()方法。而現在的Android手機幾乎都沒有鍵盤了,因此基本上只可以使用requestFocus()這個辦法來讓視圖獲得焦點了。而requestFocus()方法也不能保證一定可以讓視圖獲得焦點,它會有一個布爾值的返回值,如果返回true說明獲得焦點成功,返回false說明獲得焦點失敗。一般只有視圖在focusable和focusable in touch mode同時成立的情況下才能成功獲取焦點,比如說EditText。

3. window_focused

表示當前視圖是否處于正在交互的窗口中,這個值由系統自動決定,應用程序不能進行改變。

4. selected

表示當前視圖是否處于選中狀態。一個界面當中可以有多個視圖處于選中狀態,調用setSelected()方法能夠改變視圖的選中狀態,傳入true表示選中,傳入false表示未選中。

5. pressed

表示當前視圖是否處于按下狀態。可以調用setPressed()方法來對這一狀態進行改變,傳入true表示按下,傳入false表示未按下。通常情況下這個狀態都是由系統自動賦值的,但開發者也可以自己調用這個方法來進行改變。

我們可以在項目的drawable目錄下創建一個selector文件,在這里配置每種狀態下視圖對應的背景圖片。比如創建一個compose_bg.xml文件,在里面編寫如下代碼:

[html] view plaincopy
  • <selector?xmlns:android="http://schemas.android.com/apk/res/android">??
  • ??
  • ????<item?android:drawable="@drawable/compose_pressed"?android:state_pressed="true"></item>??
  • ????<item?android:drawable="@drawable/compose_pressed"?android:state_focused="true"></item>??
  • ????<item?android:drawable="@drawable/compose_normal"></item>??
  • ??
  • </selector>??
  • 這段代碼就表示,當視圖處于正常狀態的時候就顯示compose_normal這張背景圖,當視圖獲得到焦點或者被按下的時候就顯示compose_pressed這張背景圖。

    創建好了這個selector文件后,我們就可以在布局或代碼中使用它了,比如將它設置為某個按鈕的背景圖,如下所示:

    [html] view plaincopy
  • <?xml?version="1.0"?encoding="utf-8"?>??
  • <LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"??
  • ????android:layout_width="match_parent"??
  • ????android:layout_height="match_parent"??
  • ????android:orientation="vertical"?>??
  • ??????
  • ????<Button???
  • ????????android:id="@+id/compose"??
  • ????????android:layout_width="60dp"??
  • ????????android:layout_height="40dp"??
  • ????????android:layout_gravity="center_horizontal"??
  • ????????android:background="@drawable/compose_bg"??
  • ????????/>??
  • ??????
  • </LinearLayout>??
  • 現在運行一下程序,這個按鈕在普通狀態和按下狀態的時候就會顯示不同的背景圖片,如下圖所示:


    這樣我們就用一個非常簡單的方法實現了按鈕按下的效果,但是它的背景原理到底是怎樣的呢?這就又要從源碼的層次上進行分析了。

    我們都知道,當手指按在視圖上的時候,視圖的狀態就已經發生了變化,此時視圖的pressed狀態是true。每當視圖的狀態有發生改變的時候,就會回調View的drawableStateChanged()方法,代碼如下所示:

    [java] view plaincopy
  • protected?void?drawableStateChanged()?{??
  • ????Drawable?d?=?mBGDrawable;??
  • ????if?(d?!=?null?&&?d.isStateful())?{??
  • ????????d.setState(getDrawableState());??
  • ????}??
  • }??
  • 在這里的第一步,首先是將mBGDrawable賦值給一個Drawable對象,那么這個mBGDrawable是什么呢?觀察setBackgroundResource()方法中的代碼,如下所示: [java] view plaincopy
  • public?void?setBackgroundResource(int?resid)?{??
  • ????if?(resid?!=?0?&&?resid?==?mBackgroundResource)?{??
  • ????????return;??
  • ????}??
  • ????Drawable?d=?null;??
  • ????if?(resid?!=?0)?{??
  • ????????d?=?mResources.getDrawable(resid);??
  • ????}??
  • ????setBackgroundDrawable(d);??
  • ????mBackgroundResource?=?resid;??
  • }??
  • 可以看到,在第7行調用了Resource的getDrawable()方法將resid轉換成了一個Drawable對象,然后調用了setBackgroundDrawable()方法并將這個Drawable對象傳入,在setBackgroundDrawable()方法中會將傳入的Drawable對象賦值給mBGDrawable。

    而我們在布局文件中通過android:background屬性指定的selector文件,效果等同于調用setBackgroundResource()方法。也就是說drawableStateChanged()方法中的mBGDrawable對象其實就是我們指定的selector文件。

    接下來在drawableStateChanged()方法的第4行調用了getDrawableState()方法來獲取視圖狀態,代碼如下所示:

    [java] view plaincopy
  • public?final?int[]?getDrawableState()?{??
  • ????if?((mDrawableState?!=?null)?&&?((mPrivateFlags?&?DRAWABLE_STATE_DIRTY)?==?0))?{??
  • ????????return?mDrawableState;??
  • ????}?else?{??
  • ????????mDrawableState?=?onCreateDrawableState(0);??
  • ????????mPrivateFlags?&=?~DRAWABLE_STATE_DIRTY;??
  • ????????return?mDrawableState;??
  • ????}??
  • }??
  • 在這里首先會判斷當前視圖的狀態是否發生了改變,如果沒有改變就直接返回當前的視圖狀態,如果發生了改變就調用onCreateDrawableState()方法來獲取最新的視圖狀態。視圖的所有狀態會以一個整型數組的形式返回。

    在得到了視圖狀態的數組之后,就會調用Drawable的setState()方法來對狀態進行更新,代碼如下所示:

    [java] view plaincopy
  • public?boolean?setState(final?int[]?stateSet)?{??
  • ????if?(!Arrays.equals(mStateSet,?stateSet))?{??
  • ????????mStateSet?=?stateSet;??
  • ????????return?onStateChange(stateSet);??
  • ????}??
  • ????return?false;??
  • }??
  • 這里會調用Arrays.equals()方法來判斷視圖狀態的數組是否發生了變化,如果發生了變化則調用onStateChange()方法,否則就直接返回false。但你會發現,Drawable的onStateChange()方法中其實就只是簡單返回了一個false,并沒有任何的邏輯處理,這是為什么呢?這主要是因為mBGDrawable對象是通過一個selector文件創建出來的,而通過這種文件創建出來的Drawable對象其實都是一個StateListDrawable實例,因此這里調用的onStateChange()方法實際上調用的是StateListDrawable中的onStateChange()方法,那么我們趕快看一下吧: [java] view plaincopy
  • @Override??
  • protected?boolean?onStateChange(int[]?stateSet)?{??
  • ????int?idx?=?mStateListState.indexOfStateSet(stateSet);??
  • ????if?(DEBUG)?android.util.Log.i(TAG,?"onStateChange?"?+?this?+?"?states?"??
  • ????????????+?Arrays.toString(stateSet)?+?"?found?"?+?idx);??
  • ????if?(idx?<?0)?{??
  • ????????idx?=?mStateListState.indexOfStateSet(StateSet.WILD_CARD);??
  • ????}??
  • ????if?(selectDrawable(idx))?{??
  • ????????return?true;??
  • ????}??
  • ????return?super.onStateChange(stateSet);??
  • }??
  • 可以看到,這里會先調用indexOfStateSet()方法來找到當前視圖狀態所對應的Drawable資源下標,然后在第9行調用selectDrawable()方法并將下標傳入,在這個方法中就會將視圖的背景圖設置為當前視圖狀態所對應的那張圖片了。

    那你可能會有疑問,在前面一篇文章中我們說到,任何一個視圖的顯示都要經過非常科學的繪制流程的,很顯然,背景圖的繪制是在draw()方法中完成的,那么為什么selectDrawable()方法能夠控制背景圖的改變呢?這就要研究一下視圖重繪的流程了。

    二、視圖重繪

    雖然視圖會在Activity加載完成之后自動繪制到屏幕上,但是我們完全有理由在與Activity進行交互的時候要求動態更新視圖,比如改變視圖的狀態、以及顯示或隱藏某個控件等。那在這個時候,之前繪制出的視圖其實就已經過期了,此時我們就應該對視圖進行重繪。

    調用視圖的setVisibility()、setEnabled()、setSelected()等方法時都會導致視圖重繪,而如果我們想要手動地強制讓視圖進行重繪,可以調用invalidate()方法來實現。當然了,setVisibility()、setEnabled()、setSelected()等方法的內部其實也是通過調用invalidate()方法來實現的,那么就讓我們來看一看invalidate()方法的代碼是什么樣的吧。

    View的源碼中會有數個invalidate()方法的重載和一個invalidateDrawable()方法,當然它們的原理都是相同的,因此我們只分析其中一種,代碼如下所示:

    [java] view plaincopy
  • void?invalidate(boolean?invalidateCache)?{??
  • ????if?(ViewDebug.TRACE_HIERARCHY)?{??
  • ????????ViewDebug.trace(this,?ViewDebug.HierarchyTraceType.INVALIDATE);??
  • ????}??
  • ????if?(skipInvalidate())?{??
  • ????????return;??
  • ????}??
  • ????if?((mPrivateFlags?&?(DRAWN?|?HAS_BOUNDS))?==?(DRAWN?|?HAS_BOUNDS)?||??
  • ????????????(invalidateCache?&&?(mPrivateFlags?&?DRAWING_CACHE_VALID)?==?DRAWING_CACHE_VALID)?||??
  • ????????????(mPrivateFlags?&?INVALIDATED)?!=?INVALIDATED?||?isOpaque()?!=?mLastIsOpaque)?{??
  • ????????mLastIsOpaque?=?isOpaque();??
  • ????????mPrivateFlags?&=?~DRAWN;??
  • ????????mPrivateFlags?|=?DIRTY;??
  • ????????if?(invalidateCache)?{??
  • ????????????mPrivateFlags?|=?INVALIDATED;??
  • ????????????mPrivateFlags?&=?~DRAWING_CACHE_VALID;??
  • ????????}??
  • ????????final?AttachInfo?ai?=?mAttachInfo;??
  • ????????final?ViewParent?p?=?mParent;??
  • ????????if?(!HardwareRenderer.RENDER_DIRTY_REGIONS)?{??
  • ????????????if?(p?!=?null?&&?ai?!=?null?&&?ai.mHardwareAccelerated)?{??
  • ????????????????p.invalidateChild(this,?null);??
  • ????????????????return;??
  • ????????????}??
  • ????????}??
  • ????????if?(p?!=?null?&&?ai?!=?null)?{??
  • ????????????final?Rect?r?=?ai.mTmpInvalRect;??
  • ????????????r.set(0,?0,?mRight?-?mLeft,?mBottom?-?mTop);??
  • ????????????p.invalidateChild(this,?r);??
  • ????????}??
  • ????}??
  • }??
  • 在這個方法中首先會調用skipInvalidate()方法來判斷當前View是否需要重繪,判斷的邏輯也比較簡單,如果View是不可見的且沒有執行任何動畫,就認為不需要重繪了。之后會進行透明度的判斷,并給View添加一些標記位,然后在第22和29行調用 ViewParent的invalidateChild()方法,這里的ViewParent其實就是當前視圖的父視圖,因此會調用到ViewGroup的invalidateChild()方法中,代碼如下所示: [java] view plaincopy
  • public?final?void?invalidateChild(View?child,?final?Rect?dirty)?{??
  • ????ViewParent?parent?=?this;??
  • ????final?AttachInfo?attachInfo?=?mAttachInfo;??
  • ????if?(attachInfo?!=?null)?{??
  • ????????final?boolean?drawAnimation?=?(child.mPrivateFlags?&?DRAW_ANIMATION)?==?DRAW_ANIMATION;??
  • ????????if?(dirty?==?null)?{??
  • ????????????......??
  • ????????}?else?{??
  • ????????????......??
  • ????????????do?{??
  • ????????????????View?view?=?null;??
  • ????????????????if?(parent?instanceof?View)?{??
  • ????????????????????view?=?(View)?parent;??
  • ????????????????????if?(view.mLayerType?!=?LAYER_TYPE_NONE?&&??
  • ????????????????????????????view.getParent()?instanceof?View)?{??
  • ????????????????????????final?View?grandParent?=?(View)?view.getParent();??
  • ????????????????????????grandParent.mPrivateFlags?|=?INVALIDATED;??
  • ????????????????????????grandParent.mPrivateFlags?&=?~DRAWING_CACHE_VALID;??
  • ????????????????????}??
  • ????????????????}??
  • ????????????????if?(drawAnimation)?{??
  • ????????????????????if?(view?!=?null)?{??
  • ????????????????????????view.mPrivateFlags?|=?DRAW_ANIMATION;??
  • ????????????????????}?else?if?(parent?instanceof?ViewRootImpl)?{??
  • ????????????????????????((ViewRootImpl)?parent).mIsAnimating?=?true;??
  • ????????????????????}??
  • ????????????????}??
  • ????????????????if?(view?!=?null)?{??
  • ????????????????????if?((view.mViewFlags?&?FADING_EDGE_MASK)?!=?0?&&??
  • ????????????????????????????view.getSolidColor()?==?0)?{??
  • ????????????????????????opaqueFlag?=?DIRTY;??
  • ????????????????????}??
  • ????????????????????if?((view.mPrivateFlags?&?DIRTY_MASK)?!=?DIRTY)?{??
  • ????????????????????????view.mPrivateFlags?=?(view.mPrivateFlags?&?~DIRTY_MASK)?|?opaqueFlag;??
  • ????????????????????}??
  • ????????????????}??
  • ????????????????parent?=?parent.invalidateChildInParent(location,?dirty);??
  • ????????????????if?(view?!=?null)?{??
  • ????????????????????Matrix?m?=?view.getMatrix();??
  • ????????????????????if?(!m.isIdentity())?{??
  • ????????????????????????RectF?boundingRect?=?attachInfo.mTmpTransformRect;??
  • ????????????????????????boundingRect.set(dirty);??
  • ????????????????????????m.mapRect(boundingRect);??
  • ????????????????????????dirty.set((int)?boundingRect.left,?(int)?boundingRect.top,??
  • ????????????????????????????????(int)?(boundingRect.right?+?0.5f),??
  • ????????????????????????????????(int)?(boundingRect.bottom?+?0.5f));??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}?while?(parent?!=?null);??
  • ????????}??
  • ????}??
  • }??
  • 可以看到,這里在第10行進入了一個while循環,當ViewParent不等于空的時候就會一直循環下去。在這個while循環當中會不斷地獲取當前布局的父布局,并調用它的invalidateChildInParent()方法,在ViewGroup的 invalidateChildInParent()方法中主要是來計算需要重繪的矩形區域,這里我們先不管它,當循環到最外層的根布局后,就會調用ViewRoot的invalidateChildInParent()方法了,代碼如下所示: [java] view plaincopy
  • public?ViewParent?invalidateChildInParent(final?int[]?location,?final?Rect?dirty)?{??
  • ????invalidateChild(null,?dirty);??
  • ????return?null;??
  • }??
  • 這里的代碼非常簡單,僅僅是去調用了invalidateChild()方法而已,那我們再跟進去瞧一瞧吧: [java] view plaincopy
  • public?void?invalidateChild(View?child,?Rect?dirty)?{??
  • ????checkThread();??
  • ????if?(LOCAL_LOGV)?Log.v(TAG,?"Invalidate?child:?"?+?dirty);??
  • ????mDirty.union(dirty);??
  • ????if?(!mWillDrawSoon)?{??
  • ????????scheduleTraversals();??
  • ????}??
  • }??
  • 這個方法也不長,它在第6行又調用了scheduleTraversals()這個方法,那么我們繼續跟進: [java] view plaincopy
  • public?void?scheduleTraversals()?{??
  • ????if?(!mTraversalScheduled)?{??
  • ????????mTraversalScheduled?=?true;??
  • ????????sendEmptyMessage(DO_TRAVERSAL);??
  • ????}??
  • }??
  • 可以看到,這里調用了sendEmptyMessage()方法,并傳入了一個DO_TRAVERSAL參數。了解Android異步消息處理機制的朋友們都會知道,任何一個Handler都可以調用sendEmptyMessage()方法來發送消息,并且在handleMessage()方法中接收消息,而如果你看一下ViewRoot的類定義就會發現,它是繼承自Handler的,也就是說這里調用 sendEmptyMessage()方法出的消息,會在ViewRoot的handleMessage()方法中接收到。那么趕快看一下handleMessage()方法的代碼吧,如下所示: [java] view plaincopy
  • public?void?handleMessage(Message?msg)?{??
  • ????switch?(msg.what)?{??
  • ????case?DO_TRAVERSAL:??
  • ????????if?(mProfile)?{??
  • ????????????Debug.startMethodTracing("ViewRoot");??
  • ????????}??
  • ????????performTraversals();??
  • ????????if?(mProfile)?{??
  • ????????????Debug.stopMethodTracing();??
  • ????????????mProfile?=?false;??
  • ????????}??
  • ????????break;??
  • ????......??
  • }??
  • 熟悉的代碼出現了!這里在第7行調用了performTraversals()方法,這不就是我們在前面一篇文章中學到的視圖繪制的入口嗎?雖然經過了很多輾轉的調用,但是可以確定的是,調用視圖的invalidate()方法后確實會走到performTraversals()方法中,然后重新執行繪制流程。之后的流程就不需要再進行描述了吧,可以參考 Android視圖繪制流程完全解析,帶你一步步深入了解View(二)?這一篇文章。

    了解了這些之后,我們再回過頭來看看剛才的selectDrawable()方法中到底做了什么才能夠控制背景圖的改變,代碼如下所示:

    [java] view plaincopy
  • public?boolean?selectDrawable(int?idx)?{??
  • ????if?(idx?==?mCurIndex)?{??
  • ????????return?false;??
  • ????}??
  • ????final?long?now?=?SystemClock.uptimeMillis();??
  • ????if?(mDrawableContainerState.mExitFadeDuration?>?0)?{??
  • ????????if?(mLastDrawable?!=?null)?{??
  • ????????????mLastDrawable.setVisible(false,?false);??
  • ????????}??
  • ????????if?(mCurrDrawable?!=?null)?{??
  • ????????????mLastDrawable?=?mCurrDrawable;??
  • ????????????mExitAnimationEnd?=?now?+?mDrawableContainerState.mExitFadeDuration;??
  • ????????}?else?{??
  • ????????????mLastDrawable?=?null;??
  • ????????????mExitAnimationEnd?=?0;??
  • ????????}??
  • ????}?else?if?(mCurrDrawable?!=?null)?{??
  • ????????mCurrDrawable.setVisible(false,?false);??
  • ????}??
  • ????if?(idx?>=?0?&&?idx?<?mDrawableContainerState.mNumChildren)?{??
  • ????????Drawable?d?=?mDrawableContainerState.mDrawables[idx];??
  • ????????mCurrDrawable?=?d;??
  • ????????mCurIndex?=?idx;??
  • ????????if?(d?!=?null)?{??
  • ????????????if?(mDrawableContainerState.mEnterFadeDuration?>?0)?{??
  • ????????????????mEnterAnimationEnd?=?now?+?mDrawableContainerState.mEnterFadeDuration;??
  • ????????????}?else?{??
  • ????????????????d.setAlpha(mAlpha);??
  • ????????????}??
  • ????????????d.setVisible(isVisible(),?true);??
  • ????????????d.setDither(mDrawableContainerState.mDither);??
  • ????????????d.setColorFilter(mColorFilter);??
  • ????????????d.setState(getState());??
  • ????????????d.setLevel(getLevel());??
  • ????????????d.setBounds(getBounds());??
  • ????????}??
  • ????}?else?{??
  • ????????mCurrDrawable?=?null;??
  • ????????mCurIndex?=?-1;??
  • ????}??
  • ????if?(mEnterAnimationEnd?!=?0?||?mExitAnimationEnd?!=?0)?{??
  • ????????if?(mAnimationRunnable?==?null)?{??
  • ????????????mAnimationRunnable?=?new?Runnable()?{??
  • ????????????????@Override?public?void?run()?{??
  • ????????????????????animate(true);??
  • ????????????????????invalidateSelf();??
  • ????????????????}??
  • ????????????};??
  • ????????}?else?{??
  • ????????????unscheduleSelf(mAnimationRunnable);??
  • ????????}??
  • ????????animate(true);??
  • ????}??
  • ????invalidateSelf();??
  • ????return?true;??
  • }??
  • 這里前面的代碼我們可以都不管,關鍵是要看到在第54行一定會調用invalidateSelf()方法,這個方法中的代碼如下所示: [java] view plaincopy
  • public?void?invalidateSelf()?{??
  • ????final?Callback?callback?=?getCallback();??
  • ????if?(callback?!=?null)?{??
  • ????????callback.invalidateDrawable(this);??
  • ????}??
  • }??
  • 可以看到,這里會先調用getCallback()方法獲取Callback接口的回調實例,然后再去調用回調實例的invalidateDrawable()方法。那么這里的回調實例又是什么呢?觀察一下View的類定義其實你就知道了,如下所示: [java] view plaincopy
  • public?class?View?implements?Drawable.Callback,?Drawable.Callback2,?KeyEvent.Callback,??
  • AccessibilityEventSource?{??
  • ????......??
  • }??
  • View類正是實現了 Callback接口,所以剛才其實調用的就是View中的invalidateDrawable()方法,之后就會按照我們前面分析的流程執行重繪邏輯,所以視圖的背景圖才能夠得到改變的。

    另外需要注意的是,invalidate()方法雖然最終會調用到performTraversals()方法中,但這時measure和layout流程是不會重新執行的,因為視圖沒有強制重新測量的標志位,而且大小也沒有發生過變化,所以這時只有draw流程可以得到執行。而如果你希望視圖的繪制流程可以完完整整地重新走一遍,就不能使用invalidate()方法,而應該調用requestLayout()了。這個方法中的流程比invalidate()方法要簡單一些,但中心思想是差不多的,這里也就不再詳細進行分析了。

    這樣的話,我們就將視圖狀態以及重繪的工作原理都搞清楚了,相信大家對View的理解變得更加深刻了。感興趣的朋友可以繼續閱讀

    總結

    以上是生活随笔為你收集整理的Android视图状态及重绘流程分析,带你一步步深入了解View(三)的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 亚洲人免费 | 一级丰满大乳hd高清 | 国产精品自在线 | 国产真实的和子乱拍在线观看 | 成人av一区二区在线观看 | 综合久久久 | 极品美女销魂一区二区三区 | 蜜桃精品在线观看 | 爱综合网 | 日本xxxx高清| 美女福利视频网 | 91福利免费视频 | 有码av在线 | 国产一区二区三区播放 | 免费中文字幕在线观看 | 秋霞福利片 | 欧亚一区二区 | 国产99久 | 日本欧美一区 | 草莓视频在线观看入口w | 91免费进入| 一级中文字幕 | 暴操白虎| 欧美成本人视频 | 欧美黄片一区 | 日韩视频一二三 | 97香蕉久久夜色精品国产 | 亚洲欧美影院 | 日韩欧美日本 | 台湾佬美性中文娱乐网 | 欧美高清精品一区二区 | 日本理论中文字幕 | 秘密基地在线观看完整版免费 | 性做久久久 | 天天爽夜夜爽一区二区三区 | 精品国产乱码 | 国产一区二区三区在线观看视频 | 国产精品免费电影 | 亚洲成a人片77777精品 | 九九九九九九精品 | 天堂网视频 | 欧美性aaa | 黄频在线观看 | 黄污视频网站 | 中国美女一级片 | 亚洲一区二区福利视频 | 另类中文字幕 | 色屁屁一区二区三区视频 | 人妻熟女一区二区三区app下载 | 欧美性网址| 欧美日韩性视频 | 欧洲精品一区二区三区 | 国产精品h | 日韩欧美自拍偷拍 | 中文字幕在线看人 | 精品无码一区二区三区 | 国产一区二区在线精品 | 午夜寂寞福利 | 中文字幕人妻精品一区 | 国产精品熟妇人妻g奶一区 a少妇 | 欧美黑人又粗又大高潮喷水 | 亚洲成人99 | 亚洲aⅴ乱码精品成人区 | 久久久一级黄色片 | 天天摸夜夜操 | 91精品国产综合久久久蜜臀图片 | 每日av在线| 69国产视频| 国产私密视频 | 狠狠婷 | 色香欲综合网 | 亚久久| 草草色| a级无遮挡超级高清-在线观看 | 丰满人妻一区二区三区免费视频 | 午夜裸体性播放 | 色撸撸在线观看 | 亚洲嫩草影院 | 国产成人超碰人人澡人人澡 | 黄色免费入口 | 天天看天天射 | 日韩簧片| 国产精品资源在线观看 | 日韩成人午夜 | 视频一区二区三区精品 | 精品国产一区二区在线 | 久久久亚洲综合 | 蜜芽在线视频 | 亚洲第一色网 | 久久水蜜桃 | 91超级碰| 亚洲精品在线观看免费 | 色爱五月天 | 91av色| 97在线看 | 欧美蜜桃视频 | 国内自拍真实伦在线观看 | 亚洲手机看片 | 美国少妇在线观看免费 |