国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

一文讓你理清PrimaryScrollController

移動開發
對蘋果用戶來說,大家基本都知道,iOS手機應用有一個比較常見的功能:點擊狀態欄,列表就會滾動到頂部。在iOS原生代碼中,我們可以通過原生框架的已有特性或者自己添加監聽來實現這個功能。

PrimaryScrollController的作用

對蘋果用戶來說,大家基本都知道,iOS手機應用有一個比較常見的功能:點擊狀態欄,列表就會滾動到頂部。

在iOS原生代碼中,我們可以通過原生框架的已有特性或者自己添加監聽來實現這個功能。

那么在flutter中有沒有呢?答案當然是肯定的。

flutter專門為iOS端做了這一個支持,可以讓我們快速的實現點擊狀態欄回頂部的效果,它就是一系列圍繞PrimaryScrollController數據傳遞方式所展開的設計。

按照我們早期flutter開發經驗,如果沒有仔細的對PrimaryScrollController和相關類的實現有詳細的了解,必然會在構建結構復雜的頁面時出現各種奇怪的問題。

PrimaryScrollController的定義

PrimaryScrollController的源碼內容并不多,主要包含兩部分。

  • 擴展自InheritedWidget
  • 持有ScrollController類型的變量

下面是源碼部分:

class PrimaryScrollController extends InheritedWidget {

const PrimaryScrollController({
Key? key,
required ScrollController this.controller,
required Widget child,
}) : assert(controller != null),
super(key: key, child: child);


const PrimaryScrollController.none({
Key? key,
required Widget child,
}) : controller = null,
super(key: key, child: child);

final ScrollController? controller;


static ScrollController? of(BuildContext context) {
final PrimaryScrollController? result = context.dependOnInheritedWidgetOfExactType<PrimaryScrollController>();
return result?.controller;
}
...
}

關于InheritedWidget

InheritedWidget可以說是flutter框架內比較常見的數據傳遞設計抽象,簡單介紹一下。

?

每個Element實例都持有一個_inheritedWidgets?,每當要為Widget添加特定類型的依賴時,就會從該集合里取出相關類型的InheritedElement實例。

而element的_inheritedWidgets是在每次element掛載和重新啟用時,element都會從它的上層element中打包拿到其所持有的所有_inheritedWidgets。

還有特殊的InheritedElement? 它繼承了Element?,相較于普通的Element,InheritedElement?不僅會拿到其上層element所有的_inheritedWidgets,而且會將自己也作為一個元素添加到集合中

自定義 InheritedWidgetA:

class InheritedWidgetA extends InheritedWidget {
Value a;
...
static Value? of(BuildContext context) {
final InheritedWidgetA? result =
context.dependOnInheritedWidgetOfExactType<InheritedWidgetA>();
return result?.a;
}
}

使用示例和數據傳遞如下:

圖片

inheritedWidget數據圖

如上圖所示:childA,childB都能共享上級樹的數據。

ScrollController

ScrollController?間接繼承自Listenable,主要有兩個功能

  • 監聽滾動事件
  • 控制列表滾動

ScrollController部分實現:

class ScrollController extends ChangeNotifier {
...
void jumpTo(double value) {
assert(_positions.isNotEmpty, 'ScrollController not attached to any scroll views.');
for (final ScrollPosition position in List<ScrollPosition>.of(_positions))
position.jumpTo(value);
}




void attach(ScrollPosition position) {
assert(!_positions.contains(position));
_positions.add(position);
position.addListener(notifyListeners);
}




void detach(ScrollPosition position) {
assert(_positions.contains(position));
position.removeListener(notifyListeners);
_positions.remove(position);
}

}

看源碼發現:

ScrollController?提供了綁定和解綁ScrollPosition?。 每個ScrollPosition?對應一個Scrollable?滾動視圖 ,注意ScrollController?是可以綁定多個ScrollPosition。

所以通過scrollController.position直接取值報錯可能是大多數朋友會踩的坑。

ScrollPosition get position {
assert(_positions.isNotEmpty, 'ScrollController not attached to any scroll views.');
assert(_positions.length == 1, 'ScrollController attached to multiple scroll views.');
return _positions.single;
}

ScrollView與ScrollController的聯系:

ScrollView?創建時是需要兩個參數controller和primary?的,主要用來確定綁定的scrollController是使用controller?還是最近的父級PrimaryScrollController中的scrollController。

abstract class ScrollView extends StatelessWidget {
final ScrollController? controller;
final bool primary;

@override
Widget build(BuildContext context) {
final List<Widget> slivers = buildSlivers(context);
final AxisDirection axisDirection = getDirection(context);


final ScrollController? scrollController =
primary ? PrimaryScrollController.of(context) : controller;

final Scrollable scrollable = Scrollable(
controller: scrollController,
);
...
return scrollable;
}

}

可以看到在ScrollView?中會創建Scrollable,Scrollable?會在_updatePosition?時與ScrollController?進行綁定,接著ScrollController就能控制視圖滾動,或者監聽視圖滾動。

class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, RestorationMixin
implements ScrollContext {




ScrollPosition get position => _position!;
ScrollPosition? _position;

final _RestorableScrollOffset _persistedScrollOffset = _RestorableScrollOffset();

@override
AxisDirection get axisDirection => widget.axisDirection;

late ScrollBehavior _configuration;
ScrollPhysics? _physics;
ScrollController? _fallbackScrollController;
MediaQueryData? _mediaQueryData;

ScrollController get _effectiveScrollController => widget.controller ?? _fallbackScrollController!;


void _updatePosition() {
_configuration = widget.scrollBehavior ?? ScrollConfiguration.of(context);
_physics = _configuration.getScrollPhysics(context);
if (widget.physics != null) {
_physics = widget.physics!.applyTo(_physics);
} else if (widget.scrollBehavior != null) {
_physics = widget.scrollBehavior!.getScrollPhysics(context).applyTo(_physics);
}
final ScrollPosition? oldPosition = _position;
if (oldPosition != null) {
_effectiveScrollController.detach(oldPosition);



scheduleMicrotask(oldPosition.dispose);
}

_position = _effectiveScrollController.createScrollPosition(_physics!, this, oldPosition);
assert(_position != null);
_effectiveScrollController.attach(position);
}

}

到這里已經介紹完了PrimaryScrollController?的實現以及相關的類與其的關系,接下來,我們看一下Flutter官方是怎么利用PrimaryScrollController?來設計點擊狀態欄回頂部功能的,看看Flutter還在哪些內部組件埋下了關于PrimaryScrollController的處理。

Scaffold

到目前為止,我們只談了PrimaryScrollController的使用,那么思考一下:點擊狀態欄事件的監聽是在哪里實現的?是如何對應到每個具體頁面的?

你猜對了,在Scaffold中。Scaffold是基于Material上的一種視覺支架,可以很方便的作出類似iOS風格的交互和UI。Flutter官方在Scaffold中添加了狀態欄區域的gesture并處理了點擊事件。看源碼:

class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, RestorationMixin {

@override
Widget build(BuildContext context) {
...
switch (themeData.platform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
_addIfNonNull(
children,
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: _handleStatusBarTap,

excludeFromSemantics: true,
),
_ScaffoldSlot.statusBar,
removeLeftPadding: false,
removeTopPadding: true,
removeRightPadding: false,
removeBottomPadding: true,
);
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
break;
}
...
}




void _handleStatusBarTap() {
final ScrollController? _primaryScrollController = PrimaryScrollController.of(context);
if (_primaryScrollController != null && _primaryScrollController.hasClients) {
_primaryScrollController.animateTo(
0.0,
duration: const Duration(milliseconds: 300),
curve: Curves.linear,
);
}
}

}

可以看到,Scaffold中添加了狀態欄位置的點擊,并在點擊后通過 PrimaryScrollController.of(context) 獲取scrollController,最后調整滾動位置。

此時我們已經知道了狀態欄監聽使用PrimaryScrollController.of(context)?進行了控制滾動,ScrollView 綁定了PrimaryScrollController.of(context) 。

好了,到目前為止,我們可以看下面的例子:一般情況下我們的項目代碼是下面這樣

runApp(
MaterialApp(
theme: ThemeData(
platform: TargetPlatform.iOS,
primarySwatch: Colors.blue,
),
routes: kkConfigureRoutes(),
initialRoute: "/",
)
);


class PageAState {
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
child:ListView(
primary:true
controller:null
...
)
);
}
}

當你push到PageA時,接著點擊狀態欄,PageA中的列表回到了頂部。感覺好像沒什么問題,但是好像缺了點什么,對嗎?

對!?? 你發現了,我們并沒有創建PrimaryScrollController? 和 Scrollcontroller。那么Scaffold中取的PrimaryScrollController來自哪里?

PrimaryScrollController  的默認創建

在上面PageAState中你會發現:PrimaryScrollController.of(context) 是有值的。所以答案只能是在push到頁面pageA時,就創建了PrimaryScrollController和Scrollcontroller。猜測flutter應該是在router層給大家自動創建了。我們尋找一下源碼,發現在routes.dart的_ModalScope中,套了一層 PrimaryScrollController(controller:primaryScrollController)。

class _ModalScopeState<T> extends State<_ModalScope<T>> {




....
final ScrollController primaryScrollController = ScrollController();

@override
Widget build(BuildContext context) {
return ...
child: PrimaryScrollController(
controller: primaryScrollController,
...
)
}
}

路由每產生一級ModalScopeState,會創建ScrollController(), 并添加PrimaryScrollController Widget。頁面Page作為子Wideget就可以獲取到上級的ScrollController。

使用流程小結

上面講了這么多,現在我們可以總結一下,正確優雅的使用官方提供的點擊狀態欄功能的步驟:

  • 需要通過路由進了頁面
  • 頁面需要使用Scaffold, 這里注意(同一個頁面Scaffold不能嵌套,否則可能無法響應狀態欄點擊事件)
  • Scaffold中有ScrollView
  • PrimaryScrollController.of(context) 綁定了ScrollView

這樣就實現了點擊狀態欄滾動視圖回到頂部功能。

實際問題

我們來看一個比較常見的App結構:打開app,app底部有三個tab,每個tab都有對應的A,B兩個列表頁。下面是代碼:

void main {
runApp(
MaterialApp(
routes: kkConfigureRoutes(),
initialRoute: "/",
)
);
}



class RootTabPageState extends BaseThemeState<RootTabPage> {

late PageController _pageController;
late List<Widget> _tabs;

@override
void initState() {
super.initState();
_tabs = [
PageA(key: _),
PageB(key: _),
];
}

@override
Widget build(BuildContext context) {

return Scaffold(
child:Column(
children:[
Expanded(child: PageView(
children: _tabs,
controller: _pageController,
physics: const NeverScrollableScrollPhysics()
)),
KKBottomBar(...),
]
),
);
}

}



class PageAState with AutomaticKeepAliveClientMixin {
Widget build(BuildContext context) {
super.build(context);
return ListView(
primary:true
controller:null
...
);
}
...
}

class PageBState with AutomaticKeepAliveClientMixin {
Widget build(BuildContext context) {
super.build(context);
return ListView(
primary:true
controller:null
...
);
}
...
}

上面的代碼有點特殊問題,不知道你們發現沒有:如果我點擊狀態欄,頁面的列表會滾動到頂部嗎?分析一下,有Router層創建了PrimaryScrollController,RootTabPageState層包裝了Scaffold監聽點擊狀態欄事件,然后A,B頁面primary=true , 兩個頁面的ScrollView都綁定了父PrimaryScrollController.of(context)。所以點擊狀態欄,列表會回到頂部。但是你會發現PrimaryScrollController.of(context) 綁定了兩個ScrollView。所以點擊狀態欄,兩個列表都會回到頂部,當然如果需求是這樣,那么沒問題,但是我想大部分情況下這是一個問題。所以,我們來試著改一下:

class RootTabPageState extends BaseThemeState<RootTabPage> {

late PageController _pageController;
late List<Widget> _tabs;

@override
void initState() {
super.initState();
_tabs = [
PageA(key: _),
PageB(key: _),
PageC(key: _),
];
}

@override
Widget build(BuildContext context) {

return Material(
child:Column(
children:[
Expanded(child: PageView(
children: _tabs,
controller: _pageController,
physics: const NeverScrollableScrollPhysics()
)),
KKBottomBar(...),
]
),
);
}

}

class PageAState {
Widget build(BuildContext context) {
return Scaffold(
ListView(
primary:true
controller:null
...
)
);
}
...
}

class PageBState {
Widget build(BuildContext context) {

return Scaffold(
ListView(
primary:true
controller:null
...
)
);
}
...
}

我們將RootTabPageState中的Scaffold改成了Material,A,B頁面加上了Scaffold。想想結果是什么?雖然我們添加了兩個Scaffold監聽各自的頁面A,B。但是PrimaryScrollController.of(context) ,其實是Router層創建的,所以PrimaryScrollController.of(context) 還是綁定了兩個頁面的ScrollView。所以點擊狀態欄,兩個列表都會回到頂部。我們繼續調整:

class RootTabPageState extends BaseThemeState<RootTabPage> {

late PageController _pageController;
late List<Widget> _tabs;

@override
void initState() {
super.initState();
_tabs = [
PageA(key: _),
PageB(key: _),
PageC(key: _),
];
}

@override
Widget build(BuildContext context) {

return Material(
child:Column(
children:[
Expanded(child: PageView(
children: _tabs,
controller: _pageController,
physics: const NeverScrollableScrollPhysics()
)),
KKBottomBar(...),
]
),
);
}

}

class PageAState {

final ScrollController _scrollController = ScrollController();

Widget build(BuildContext context) {
return
PrimaryScrollController(
controller: _scrollController,
child: Scaffold(
ListView(
primary:true
controller:null
...
)
)
);
}

...
}

class PageBState {
final ScrollController _scrollController = ScrollController();

Widget build(BuildContext context) {
return
PrimaryScrollController(
controller: _scrollController,
child: Scaffold(
ListView(
primary:true
controller:null
...
)
)
);
}
...
}

我們在A,B頁面自己添加了PrimaryScrollController并創建了_scrollController,這樣PageA中的Scaffold取PrimaryScrollController.of(context) 其實取的是我們創建的_scrollController。PageA中的Scrollview綁定的也是PageA中的_scrollController。所以現在,我們在A頁面點擊狀態欄,那么只有A頁面的列表會回到頂部了。當大家真正了解了上面提到的相關內容后,在你遇到不同的頁面結構時,就知道如何去設計,才能避免一些奇怪的問題。

大家可以思考一下?在上述例子結構中,如果其中PageAState頁面不止包含一個列表,而是本身是一個可以左右滾動的多列表時,該如何實現在頁面A點擊狀態欄,讓頁面A當前顯示的列表回到頂部。

篇幅有限,這里給提供一個思路,每個列表單獨創建ScrollController。PageA層自定義ScrollController類,重寫其滾動方法來接受狀態欄點擊事件,下發到對應列表的ScrollController。

隱秘的問題

接下來,說一個比較隱秘的問題,下面是一個例子:

class PageAState {
final ScrollController _scrollController = ScrollController();

Widget build(BuildContext context) {
super.build(context);
return
PrimaryScrollController(
controller: _scrollController,
Scaffold(
child:ListView(
primary:true
controller:null,
children:[
CellA()
])

);
}
}


class CellAState {

ScrollController? _controller;
@override
Widget build(BuildContext context) {
_controller = PrimaryScrollController.of(context);
return MyButton(
onPress:_press
);
}

void _press(){
_controller?.jumpTo(0);
}
}

上面這個例子中,我想在CellAState中獲取_controller,然后用它來做點事情,比如里面有個按鈕,然后點擊后,讓列表滾動到某個位置。雖然這個例子看起來非常簡單,但是很不幸,你取到的_controller為null,為什么?此時你會檢查代碼,檢查PrimaryScrollController的使用方式是否有問題,在檢查了一輪之后,發現并沒有問題,然后你可能開始有點抓狂。這個例子層級少,比較簡單的,我們可以也許可以通過斷點發現一些端倪,但是在項目中可能層級非常之多,如果通過斷點去找,那將是地獄。沒有辦法,你只能進入地獄,很幸運我們的例子很簡單,這個地獄不是特別深,通過斷點一步一步的,你會發現有一個 PrimaryScrollController.none,回顧一下,這個東西好像在PrimaryScrollController的源碼中出現過。

這個東西是在哪創建的呢???

因為我們例子比較簡單,所以我們能肯定問題發生在List中,但是在項目中這將是一個非常隱秘的問題。我們進入listView, 一層層的進入,最后看到了它的抽象類ScrollView,我們之前提到過。我們再來看下ScrollView的源碼:

abstract class ScrollView extends StatelessWidget {
final ScrollController? controller;
final bool primary;
const ScrollView({
Key? key,
this.controller,
bool? primary,
...
}) : assert(scrollDirection != null),
assert(!(controller != null && (primary ?? false)),
'Primary ScrollViews obtain their ScrollController via inheritance from a PrimaryScrollController widget. '
'You cannot both set primary to true and pass an explicit controller.',
),
primary = primary ?? controller == null && identical(scrollDirection, Axis.vertical),
super(key: key);

@override
Widget build(BuildContext context) {
...
final ScrollController? scrollController =
primary ? PrimaryScrollController.of(context) : controller;
final Scrollable scrollable = Scrollable(
...
);
final Widget scrollableResult = primary && scrollController != null
? PrimaryScrollController.none(child: scrollable)
: scrollable;
...
return scrollableResult;
}

}

我們發現了什么?

final Widget scrollableResult = primary && scrollController != null
? PrimaryScrollController.none(child: scrollable)
: scrollable;

在 primary && scrollController != null的情況下它為我們包裝了一層PrimaryScrollController.none(child: scrollable)  等效于 PrimaryScrollController(controller:null,child:scrollable)。也就是按照我們外部傳prmary = true的情況下,它把我們截斷了。所以回到我們的問題,如果我們要在CellA中想通過PrimaryScrollController.of(context)取值,該如何修改?

class PageAState {
final ScrollController _scrollController = ScrollController();


Widget build(BuildContext context) {
super.build(context);
return
PrimaryScrollController(
controller: _scrollController,
Scaffold(
child:ListView(
primary:false
controller:_scrollController,
children:[
CellA()
])

);
}
}


class CellAState {

ScrollController? _controller;
@override
Widget build(BuildContext context) {
_controller = PrimaryScrollController.of(context);
return MyButton(
onPress:_press
);
}

void _press(){
_controller?.jumpTo(0);
}
}

結語

好了,本篇基本已經到了尾聲了,相信大家以后碰到與PrimaryScrollController相關的問題便不再是問題了。

看完了這一系列內容,我們可以發現PrimaryScrollController?只是flutter設計的一種數據傳遞的方案,只是解決點擊狀態欄使列表滾動到頂部這個問題中的一環。整個問題其實是涉及到了ScroView,ScrollController,Scaffold?以及Router中的_ModalScopeState等,它們或多或少的提供了特殊處理和輔助方式。

不得不說flutter的組件提供了非常強大的功能,但這也可能導致看似無關的組件和類之間,內部其實是有一定聯系的,而且比較隱蔽,所以在部分復雜場景下,可能會出現一些問題,這時候就比較考驗開發者耐心和對各種組件源碼的熟悉度了。

責任編輯:未麗燕 來源: 搜狐技術產品
相關推薦

2025-05-21 09:32:28

2025-06-04 03:21:00

RAGRetrievalGeneratio

2023-03-10 22:08:20

2018-05-21 10:20:22

人工智能機器學習神經網絡

2018-02-02 11:17:42

IaaSPaaSSaaS

2018-05-31 20:49:50

Spark堆內內存優化機制

2024-09-26 07:27:27

2018-06-13 08:33:32

車聯網智能交通互聯網

2021-10-20 08:49:30

Vuexvue.js狀態管理模式

2020-11-12 09:14:25

JAVA.IO、字符編

2019-07-03 15:32:26

路由器網絡系統

2019-11-06 17:00:51

深度學習神經網絡人工智能

2018-02-03 09:59:20

python程序編輯器

2021-01-21 14:26:56

大數據互聯網大數據應用

2022-03-18 09:45:43

Git分支Linux

2018-10-08 15:00:27

物聯網LoRaIOT

2021-09-10 16:10:21

panda透視表語言

2025-05-22 06:23:48

2025-06-17 00:00:00

2025-01-17 10:49:44

數字化轉型數字化企業管理
點贊
收藏

51CTO技術棧公眾號

国产精品免费一区二区三区都可以| 久久亚洲精品网站| 久久69国产一区二区蜜臀| 国产劲爆久久| 精品91福利视频| vam成人资源在线观看| 91av亚洲| 97欧美成人| 精品一区91| 精品视频亚洲| 亚洲特级毛片| 国内精品视频一区二区三区八戒| 91麻豆精品视频| 懂色av中文一区二区三区天美 | 精品视频一区二区三区在线观看| 电影在线观看一区二区| 黄色精品视频网站| 国精产品一区一区三区mba桃花| 国产一区视频导航| 精品久久久一区二区| 日韩欧美一级二级三级| 深夜福利在线观看直播| 国产精品美女久久久久久久| 久久亚洲国产成人精品无码区| 国产一区二区在线网站| 亚洲国产一成人久久精品| 国产男人精品视频| 中文字幕一区二区av| 99久久精品免费看国产一区二区三区 | 视频在线观看免费高清| 国产精品18久久久久久久久| 国产精品日韩三级| av网站免费线看精品| 亚洲精品怡红院| 亚洲欧美日韩在线| 你懂的视频在线免费| 51精品国自产在线| 中国字幕a在线看韩国电影| 日韩最新免费不卡| 亚洲制服一区| 精品国产乱码一区二区三区四区| 免费视频最近日韩| 777久久久精品一区二区三区| 国产精品久久久一区麻豆最新章节| 嫩草影院在线观看网站成人| 精品欧美国产一区二区三区| 国产最新在线| 亚洲一级一级97网| www.久久东京| 91香蕉电影院| 美女在线观看视频一区二区| 自拍日韩亚洲一区在线| 亚洲精品国久久99热| 在线国产91| 日韩专区中文字幕| 日韩免费久久| 中文字幕久久综合| 欧美韩国日本一区| 欧美jizzhd69巨大| 精品自在线视频| 欧美1区免费| 久激情内射婷内射蜜桃| 精品福利一区二区| 激情亚洲小说| 国产精品v欧美精品∨日韩| 国产高清精品网站| 在线视频国产三级| 亚洲人成绝费网站色www| 国产中文字幕一区二区三区| 天堂va久久久噜噜噜久久va| 中文字幕免费不卡在线| 午夜伦理在线视频| 日本中文字幕成人| 国产麻豆视频一区| 你懂的在线看| 久久99久久亚洲国产| 亚洲一区成人| 91短视频在线| 视频直播国产精品| 国语自产精品视频在线看8查询8| 97碰在线视频| 7777精品伊人久久久大香线蕉完整版| 都市激情亚洲欧美| 在线国产99| 欧美日韩一区二区在线观看 | 日韩av网站导航| 精品国精品国产自在久国产应用| 中文字幕一区二区中文字幕| 精品国产成人av| 亚洲欧洲二区| 亚洲欧美影院| 欧美性生交片4| 另类图片第一页| 艳母动漫在线免费观看| 在线精品视频免费观看| 日韩极品少妇| 黄色动漫网站入口| 精品福利视频一区二区三区| 欧美久久影院| 最新av电影| 91精品国产高清久久久久久久久| 国产成人a级片| 2021中文字幕在线| 久久久久se| 日本福利一区二区| 国产电影一区二区在线观看| 亚洲一区二区三区四区五区xx| 国产午夜一区二区| 久久电影网电视剧免费观看| 免费看男男www网站入口在线 | 欧美日韩综合精品| 亚洲亚洲精品在线观看| 97一区二区国产好的精华液| 阿v天堂2018| 亚洲精品综合精品自拍| 日本成人在线电影网| 成人午夜在线影视| 精品久久久久久乱码天堂| 欧美视频中文字幕在线| 蜜臀久久99精品久久一区二区| 熟妇人妻va精品中文字幕| 中文字幕久热精品在线视频| 国产成人免费视频| 国产极品一区| 亚洲人成色77777| 欧美二区乱c黑人| 久久久久久久电影| 一区二区三区在线资源| 91福利国产成人精品播放| 欧美极品第一页| 国产精品久久午夜| 欧美18免费视频| 男女18免费网站视频| 国产极品精品在线观看| 夜夜爽夜夜爽精品视频| 欧美亚洲精品在线| 深夜福利在线看| 久久久99国产精品免费| 欧美一区二区三区的| 免费的成人av| 成人黄色图片网站| 国产三级三级三级看三级| 韩国日本不卡在线| 亚洲高清免费观看| 亚洲大片在线| 成全电影大全在线观看| 免费看污污视频| 欧美裸身视频免费观看| 中文字幕乱码亚洲无线精品一区| 久草视频视频在线播放| 欧美日韩一区在线播放| 精品亚洲精品福利线在观看| 成人美女视频在线观看| 国内精品视频| 国产超碰精品在线观看| 极品尤物一区二区三区| 亚洲福利视频网站| 成人激情午夜影院| 色婷婷狠狠五月综合天色拍| 日本一区高清| av电影一区二区三区| 午夜精品一区二区三区在线视 | 六十路在线观看| 日本婷婷久久久久久久久一区二区| 精品久久国产老人久久综合| a级高清视频欧美日韩| 日韩美女毛片| 香蕉网站在线观看| 污视频在线免费观看一区二区三区| 中文字幕一区电影| 亚洲一区二区视频在线观看| 久久精品观看| 精品视频一区二区三区在线观看 | 一区二区三区中文在线| 亚洲精选成人| 高清一区二区三区av| 最近中文字幕在线中文视频| 亚洲成人一区二区三区| 欧美极品欧美精品欧美视频| 欧美亚洲国产一区二区三区| 丁香啪啪综合成人亚洲小说| 区一区二视频| 超碰国产一区| 色视频www在线播放| 免费极品av一视觉盛宴| 国产色综合天天综合网| 亚洲精品中文字幕av| 午夜精品福利一区二区三区av| 精品无码三级在线观看视频 | 成人免费毛片aaaaa**| 99久久这里只有精品| 夜鲁夜鲁夜鲁视频在线播放| 黄网址在线播放免费| 五月天久久狠狠| 日韩免费观看网站| 日韩va亚洲va欧洲va国产| 亚洲国产成人tv| www激情久久| 亚洲欧美日韩视频二区| 精品在线播放|