新聞中心
Flutter了解之手勢
描述了屏幕上指針(觸摸、鼠標(biāo)、觸控筆)的位置和移動(dòng)。
創(chuàng)新互聯(lián)主要從事成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)倉山,10年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18982081108
Flutter中可以使用Listener(功能性組件)來監(jiān)聽原始觸摸事件
例1
例2
例3
忽略PointerEvent
手勢: 描述由一個(gè)或多個(gè)指針移動(dòng)組成的語義動(dòng)作,如拖動(dòng)、縮放、雙擊等。
Material大多數(shù)widget已經(jīng)對tap或手勢做出了響應(yīng)。 例如 IconButton和 FlatButton 響應(yīng)單擊,ListView響應(yīng)滑動(dòng)事件觸發(fā)滾動(dòng)。
用于手勢識別的功能性組件,通過它可以來識別各種手勢。
例(單擊)
例(添加Material觸摸水波效果 InkWell組件)
例(滑動(dòng)關(guān)閉 Dismissable組件)
例(單擊、雙擊、長按)
例(滑動(dòng))
例(掃動(dòng)---單一方向)
例(縮放)
GestureRecognizer是一個(gè)抽象類。
一種手勢的識別器對應(yīng)一個(gè)GestureRecognizer的子類。
例
由于手勢競爭最終只有一個(gè)勝出者,所以,當(dāng)有多個(gè)手勢識別器時(shí),可能會(huì)產(chǎn)生沖突。
例
例
在APP中經(jīng)常會(huì)需要一個(gè)廣播機(jī)制,用以跨頁面通知。比如一個(gè)需要登錄的APP中,頁面會(huì)關(guān)注用戶登錄或注銷事件,來進(jìn)行一些狀態(tài)更新。
這時(shí)候,一個(gè)事件總線便會(huì)非常有用,事件總線通常實(shí)現(xiàn)了訂閱者模式,訂閱者模式包含發(fā)布者和訂閱者兩種角色,可以通過事件總線來觸發(fā)事件和監(jiān)聽事件。
對于一些簡單的應(yīng)用,事件總線是足以滿足業(yè)務(wù)需求的,如果決定使用狀態(tài)管理包的話,一定要想清楚APP是否真的有必要使用它,防止“化簡為繁”、過度設(shè)計(jì)。
例
在widget樹中,每一個(gè)節(jié)點(diǎn)都可以分發(fā)通知,通知會(huì)沿著當(dāng)前節(jié)點(diǎn)向上傳遞,所有父節(jié)點(diǎn)都可以通過NotificationListener來監(jiān)聽通知。
Flutter中將這種由子向父的傳遞通知的機(jī)制稱為通知冒泡(Notification Bubbling)。
通知冒泡和用戶觸摸事件冒泡是相似的,但有一點(diǎn)不同:通知冒泡可以中止,但用戶觸摸事件不行。
通知冒泡和Web開發(fā)中瀏覽器事件冒泡原理是相似的,都是事件從出發(fā)源逐層向上傳遞,可以在上層節(jié)點(diǎn)任意位置來監(jiān)聽通知/事件,也可以終止冒泡過程,終止冒泡后,通知將不會(huì)再向上傳遞。
Flutter的UI框架實(shí)現(xiàn)中,除了在可滾動(dòng)組件在滾動(dòng)過程中會(huì)發(fā)出ScrollNotification之外,還有一些其它的通知,如SizeChangedLayoutNotification、KeepAliveNotification 、LayoutChangedNotification等,F(xiàn)lutter正是通過這種通知機(jī)制來使父元素可以在一些特定時(shí)機(jī)來做一些事情。
例
例
例
阻止冒泡
通知冒泡原理
Flutter真香,我用它寫了個(gè)桌面版JSON解析工具
Flutter支持穩(wěn)定的桌面設(shè)備開發(fā)已經(jīng)一段時(shí)間了,不得不說,F(xiàn)lutter多平臺支持的特性真的很香。我本人并沒有任何桌面開發(fā)的經(jīng)驗(yàn),但仍然使用Flutter開發(fā)出了一個(gè)桌面版小程序,功能很簡單,就是對輸入的json做格式化處理和轉(zhuǎn)模型。
話不多說,先來看看實(shí)際效果。 項(xiàng)目源碼地址
開發(fā)環(huán)境如下:
Flutter : 2.8.1
Dart : 2.15.1
IDE : VSCode
JSON作為我們?nèi)粘i_發(fā)工作中經(jīng)常要打交道的一種數(shù)據(jù)格式,它共有6種數(shù)據(jù)類型: null , num , string , object , array , bool 。我們勢必對它又愛又恨。愛他因?yàn)樗鳛閿?shù)據(jù)處理的一種格式確實(shí)非常方便簡潔。但是在我們做Flutter開發(fā)中,又需要接觸到j(luò)son解析時(shí),就會(huì)感覺非常棘手,因?yàn)閒lutter沒有反射,導(dǎo)致json轉(zhuǎn)模型這塊需要手寫那繁雜的映射關(guān)系。就像下面這樣子。
數(shù)據(jù)量少還能接受,一旦量大,那么光手寫這個(gè)解析方法都能讓你懷疑人生。更何況手寫還有出錯(cuò)的可能。好在官方有個(gè)工具**json_serializable**可以自動(dòng)生成這塊轉(zhuǎn)換代碼,也解決了flutter界json轉(zhuǎn)模型的空缺。當(dāng)然,業(yè)界也有專門解析json的網(wǎng)站,可以自動(dòng)生成dart代碼,使用者在生成后復(fù)制進(jìn)項(xiàng)目中即可,也是非常方便的。
本項(xiàng)目以json解析為切入點(diǎn),和大家一起來看下flutter是如何開發(fā)桌面應(yīng)用的。
要讓我們的flutter項(xiàng)目支持桌面設(shè)備。我們首先需要修改下flutter的設(shè)置。如下,讓我們的項(xiàng)目支持 windows 和 macos 系統(tǒng)。
接下來使用 flutter create 命令創(chuàng)建我們的模版工程。
創(chuàng)建完項(xiàng)目后,我們就可以 run 起來了。
先來看下整體界面,界面四塊,分別為功能模塊、文件選擇模塊、輸入模塊、輸出模塊。
我們在新建一個(gè)桌面應(yīng)用時(shí),默認(rèn)的模版又一個(gè)Appbar,此時(shí)應(yīng)用可以用鼠標(biāo)拖拽移動(dòng),放大縮小,還可以縮到很小。但是,我們一旦去掉這個(gè)導(dǎo)航欄,那么窗口就不能用鼠標(biāo)拖動(dòng)了,并且我們往往不希望用戶將我們的窗口縮放的很小,這會(huì)導(dǎo)致頁面異常,一些重要信息都展示不全。因此這里需要借助第三方組件 bitsdojo_window 。通過 bitsdojo_window ,我們可以實(shí)現(xiàn)窗口的定制化,拖動(dòng),最小尺寸,最大尺寸,窗口邊框,窗口頂部放大、縮小、關(guān)閉的按鈕等。
通過 InkWell 組件,可以捕捉到手勢、鼠標(biāo)、觸控筆的移動(dòng)和停留位置
這個(gè)功能是鼠標(biāo)移動(dòng)后的UI交互界面。要在窗口上顯示一個(gè)提示框,可以使用 Overlay 。需要注意的是,由于在 Overlay 上的 text 的根結(jié)點(diǎn)不是 Material 風(fēng)格的組件,因此會(huì)出現(xiàn)黃色的下劃線。因此一定要用 Material 包一下 text 。并且你必須給創(chuàng)建的 OverlayEntry 一個(gè)位置,否則它將全屏顯示。
讀取說表拖拽的文件一開始想嘗試使用 InkWell 組件,但是這個(gè)組件無法識別拖拽中的鼠標(biāo),并且也無法從中拿到文件信息。因此放棄。后來從文章《Flutter-2天寫個(gè)桌面端APP》中發(fā)現(xiàn)一個(gè)可讀取拖拽文件的組件 desktop_drop ,能滿足要求。
使用開源組件 file_picker ,選完圖片后的操作和拖拽選擇圖片后的操作一致。
Textfield 如果要顯示富文本,那么需要自定義 TextEditingController 。并重寫 buildTextSpan 方法。
在做導(dǎo)出功能時(shí)遇到下列報(bào)錯(cuò),保存提示為沒有權(quán)限訪問對應(yīng)目錄下的文件。
通過Apple的開發(fā)文檔找到有關(guān)權(quán)限問題的說明。其中有個(gè)授權(quán)私鑰的key為 com.apple.security.files.downloads.read-write ,表示 對用戶的下載文件夾的讀/寫訪問權(quán)限 。那么,使用Xcode打開Flutter項(xiàng)目中的mac應(yīng)用,修改工程目錄下的 DebugProfile.entitlements 文件,向 entitlements 文件中添加 com.apple.security.files.downloads.read-write ,并將值設(shè)置為YES,保存后重啟Flutter項(xiàng)目。發(fā)現(xiàn)已經(jīng)可以向下載目錄中讀寫文件了。
當(dāng)然,這是正常操作。還有個(gè)騷操作就是關(guān)閉系統(tǒng)的沙盒機(jī)制。將 entitlements 文件的 App Sandbox 設(shè)置為NO。這樣我們就可以訪問任意路徑了。當(dāng)然關(guān)閉應(yīng)用的沙盒也就相當(dāng)于關(guān)閉了應(yīng)用的防護(hù)機(jī)制,因此這個(gè)選項(xiàng)慎用。
原文地址:
Flutter(五)手勢GestureDetector
在Android中,每一個(gè) View 都可以通過 onTouch 方法重寫其觸摸事件,也可以通過 setOnClickListener 方法來給 View 設(shè)置點(diǎn)擊事件。但是Flutter中除了少部分組件,如 Button 相關(guān)的組件可以直接通過 onPressed 實(shí)現(xiàn)點(diǎn)擊事件。其余組件想實(shí)現(xiàn)點(diǎn)擊、長按等事件,都需要借助 GestureDetector 來實(shí)現(xiàn)手勢監(jiān)聽
下面介紹比較常用的手勢如 onTap (點(diǎn)擊)、 onDoubleTap (雙擊)、 onLongPress (長按)
小球跟隨手指移動(dòng)的實(shí)現(xiàn)應(yīng)該是屬于各種移動(dòng)端框架作為了解拖動(dòng)手勢的的典型案例,下面我們來看看用flutter如何實(shí)現(xiàn)小球跟隨手指移動(dòng)
拖動(dòng)手勢主要由 onPanDown (手指按下)、 onPanUpdate (手指滑動(dòng))、 onPanEnd (滑動(dòng)結(jié)束)構(gòu)成
縮放手勢需要用到 onScaleUpdate 方法,下面是一個(gè)簡單的圖片縮放的實(shí)現(xiàn)
Flutter手勢(粘貼即用 flutter 1.22.6)
import 'package:flutter/material.dart';
void main() = runApp(MyApp());
class MyAppextends StatelessWidget {
// This widget is the root of your application.
@override
Widgetbuild(BuildContext context) {
return MaterialApp(
title:'Flutter Demo',
? theme:ThemeData(
primarySwatch: Colors.blue, splashColor: Colors.transparent),
? home:HYHomePage(),
);
}
}
class HYHomePageextends StatelessWidget {
@override
Widgetbuild(BuildContext context) {
return Scaffold(
appBar:AppBar(
title:Text("列表測試"),
? ),
? body:GestureDemo(),
? // Center(
//? child: Stack(
//? ? alignment: Alignment.center,
//? ? children: [
//? ? ? GestureDetector(
//? ? ? ? onTapDown: (details) {
//? ? ? ? ? print("outer click");
//? ? ? ? },
//? ? ? ? child: Container(
//? ? ? ? ? width: 200,
//? ? ? ? ? height: 200,
//? ? ? ? ? color: Colors.yellow,
//? ? ? ? ? alignment: Alignment.center,
//? ? ? ? ),
//? ? ? ),
//? ? ? IgnorePointer(
//? ? ? ? child: GestureDetector(
//? ? ? ? ? onTapDown: (details) {
//? ? ? ? ? ? print("inner click");
//? ? ? ? ? },
//? ? ? ? ? child: Container(
//? ? ? ? ? ? width: 100,
//? ? ? ? ? ? height: 100,
//? ? ? ? ? ? color: Colors.red,
//? ? ? ? ? ),
//? ? ? ? ),
//? ? ? )
//? ? ],
//? ),
// ),
);
}
}
class GestureDemoextends StatelessWidget {
const GestureDemo({
Key key,
}) :super(key: key);
@override
Widgetbuild(BuildContext context) {
return Center(
child:GestureDetector(
onTapDown: (details) {
print("手指按下");
? ? ? print(details.globalPosition);
? ? ? print(details.localPosition);
? ? },
? ? onTapUp: (details) {
print("手指抬起");
? ? },
? ? onTapCancel: () {
print("手勢取消");
? ? },
? ? onTap: () {
print("手勢點(diǎn)擊");
? ? },
? ? onDoubleTap: () {
print("手指雙擊");
? ? },
? ? onLongPress: () {
print("長按手勢");
? ? },
? ? onPanUpdate: (value){
print('當(dāng)前我在滑動(dòng)$value');
? ? },
? ? child:Container(
width:200,
? ? ? height:200,
? ? ? color: Colors.orange,
? ? ),
? ),
);
}
}
class ListenerDemoextends StatelessWidget {
const ListenerDemo({
Key key,
}) :super(key: key);
@override
Widgetbuild(BuildContext context) {
return Listener(
onPointerDown: (event) {
print("指針按下:$event");
? ? print(event.position);
? ? print(event.localPosition);
? },
? onPointerMove: (event) {
//? ? ? ? ? ? print("指針移動(dòng):$event");
? },
? onPointerUp: (event) {
//? ? ? ? ? ? print("指針抬起:$event");
? },
? child:Container(
width:200,
? ? height:200,
? ? color: Colors.red,
? ),
);
}
}
Flutter 手勢指紋解鎖
??在最近做的一個(gè)Flutter項(xiàng)目中,需要用到手勢、指紋解鎖,這種需求在原生應(yīng)用中非常常見,但Flutter中手勢密碼解鎖現(xiàn)有庫比較少、官方也僅提供有一個(gè) local_auth 指紋庫,所以就自己寫了個(gè)手勢庫。
??其實(shí)實(shí)現(xiàn)這個(gè)自定義的手勢控件有很多思路,首先想到的是,要在View中創(chuàng)建9個(gè)圓,那么使用GridView再合適不過了,但是經(jīng)過嘗試,放棄了,這會(huì)使交互跟邏輯變的更加復(fù)雜,所以還是選擇直接繼承Widget,自己處理邏輯與手勢,那么下面就是需要處理的邏輯:
由于官方插件庫已經(jīng)提供有 local_auth 庫,在這里就不大贅述,具體使用就參考Flutter官方local_auth插件庫。
??如果在使用過程遇到問題,歡迎下方留言交流。
?? Pub 庫地址
名稱欄目:關(guān)于flutter識別手勢的信息
網(wǎng)址分享:http://www.dlmjj.cn/article/dscjhie.html