欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Flutter實(shí)現(xiàn)手勢(shì)密碼加密與解鎖功能

 更新時(shí)間:2022年04月28日 08:40:21   作者:老李code  
這篇文章主要介紹了如何利用Flutter實(shí)現(xiàn)手勢(shì)密碼的加密與解鎖,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

前言

密碼的由來(lái):在公元前405年,由古希臘和斯巴達(dá)的戰(zhàn)爭(zhēng)中,由于斯巴達(dá)盟友波斯帝國(guó)背叛,導(dǎo)致古希臘和斯巴達(dá)兩敗俱傷,這時(shí)斯巴達(dá)抓了一個(gè)波斯國(guó)的信使,這個(gè)信使 沒(méi)有任何情報(bào),只有一條有著雜亂無(wú)章的希臘字母的普通腰帶,最終斯巴達(dá)統(tǒng)帥破解了這條腰帶,成功擊敗了希臘。這就是世界上最早的密碼。同時(shí)也是世界上最早的解密。

密碼在我們生活中無(wú)處不在,作為個(gè)人隱私的最后一道防線顯得無(wú)比的重要,現(xiàn)在世界有各種各樣形形色色的密碼,解密方式也是層出不窮,加密,解密的過(guò)程里充滿了數(shù)學(xué)以及計(jì)算機(jī)的知識(shí),而現(xiàn)在手機(jī)的加密的方式也有很多、數(shù)字、手勢(shì)、指紋、人臉、虹膜等等方式多種多樣,有加密就有解密、有破譯等等,有些App為了安全起見(jiàn),例如招商銀行的銀行類的App在每次啟動(dòng)的時(shí)候都需要解鎖驗(yàn)證身份,那么今天我們用Flutter實(shí)現(xiàn)一個(gè)其中的加密方式,手勢(shì)密碼。

知識(shí)點(diǎn):手勢(shì)識(shí)別、繪制、動(dòng)畫(huà)

1、繪制靜態(tài)圖形

手勢(shì)密碼一般都是九宮格的形狀,所以第一步我們先把這個(gè)輔助矩形九宮格畫(huà)出來(lái),然后在每一個(gè)格子內(nèi)就可以繪制我們喜歡的圖形了,九宮格那就很簡(jiǎn)單了。
首先我們定義一個(gè)正方形300*300 為九宮格的區(qū)域,然后對(duì)這個(gè)正方形平均分成9個(gè)小格子,我們需要找到這9個(gè)小格子的中心點(diǎn)來(lái)繪制九宮格,那么我們找到之后把每個(gè)小格子的中心用一個(gè)List存儲(chǔ)起來(lái)方便以后繪制。

代碼:

double size = 300;// 正方形邊長(zhǎng)
List<Offset> centerOffset = <Offset>[];// 九宮格中心點(diǎn)

// 上面3個(gè)
centerOffset.add(Offset(-size / 3, -size / 3));
centerOffset.add(Offset(-size / 3 + size / 3, -size / 3));
centerOffset.add(Offset(-size / 3 + size / 3 * 2, -size / 3));

// 中間3個(gè)
centerOffset.add(Offset(-size / 3, 0));
centerOffset.add(Offset(-size / 3 + size / 3, 0));
centerOffset.add(Offset(-size / 3 + size / 3 * 2, 0));

// 下面3個(gè)
centerOffset.add(Offset(-size / 3, size / 3));
centerOffset.add(Offset(-size / 3 + size / 3, size / 3));
centerOffset.add(Offset(-size / 3 + size / 3 * 2, size / 3));

接下來(lái)我們就可以用這些點(diǎn)繪制九宮格了。

核心代碼:

Paint paint = Paint()
  ..style = PaintingStyle.stroke
  ..strokeWidth = 2
  ..color = Colors.black87;

canvas.drawRect(
    Rect.fromCenter(center: Offset.zero, width: 300, height: 300), paint);

// 繪制輔助區(qū)域
_drawHelpRect(canvas, size, paint);
void _drawHelpRect(Canvas canvas, Size size, Paint paint) {
  for (int i = 0; i < centerOffset.length; i++) {
    canvas.drawRect(
        Rect.fromCenter(center: centerOffset[i], width: 100, height: 100),
        paint);
  }
}

效果圖:

得到九宮格之后,我們看到很多手勢(shì)解鎖小格子內(nèi)都是圓形,這里我們繼續(xù)在每個(gè)小格子繪制圓形圖案,

核心代碼:

// 繪制圓
_drawCirCle(canvas, size, paint);
void _drawCirCle(Canvas canvas, Size size, Paint paint) {
 for (int i = 0; i < centerOffset.length; i++) {
   canvas.drawCircle(centerOffset[i], 30, paint..color = Colors.black87);
 }
}

效果圖:

到這里基本圖形已經(jīng)繪制完了。

2、存儲(chǔ)手勢(shì)密碼數(shù)據(jù)

首先我們看下手勢(shì)解鎖一共有按下、移動(dòng)、抬起三個(gè)動(dòng)作組成,在移動(dòng)的過(guò)程中會(huì)經(jīng)過(guò)九宮格內(nèi)部的圓形區(qū)域,也就是說(shuō),在經(jīng)過(guò)圓形區(qū)域的時(shí)候,我們需要將這個(gè)數(shù)據(jù)保存下來(lái)然后通知畫(huà)布進(jìn)行更新,這里的邏輯跟我之前一篇繪制海豚那篇原理一樣,首先創(chuàng)建UnlockController類繼承ChangeNotifier。這里我們將九宮格中的每一個(gè)小格子對(duì)應(yīng)一個(gè)數(shù)字進(jìn)行封裝一下。也是之后的設(shè)置和解鎖需要保存的數(shù)據(jù)。 這樣的話我們上面的九宮格就需要修改一下了,將Offset改為PassWord就行。

數(shù)據(jù)代碼:

class UnlockController extends ChangeNotifier {
  // 存儲(chǔ)按壓的點(diǎn)集合
  List<PassWord> _points = [];

  List<PassWord> get points => _points;

  // 當(dāng)前手指的位置
  Offset? _currentOffset;

  Offset? get currentOffset => _currentOffset;

  //
  set currentOffset(Offset? value) {
    _currentOffset = value;
    notifyListeners();
  }

  addPoint(PassWord offset) {
    _points.add(offset);
    notifyListeners();
  }

  // 清除所有點(diǎn)
  clearAllPoint() {
    _points.clear();
    notifyListeners();
  }
}

class PassWord {
  int num; // 密碼數(shù)字
  Offset offset; // 密碼數(shù)字對(duì)應(yīng)的點(diǎn)
  PassWord(this.num, this.offset);
}

有了這些數(shù)據(jù)之后我們接下來(lái)就要跟手勢(shì)進(jìn)行交互了。

3、添加手勢(shì)交互

接著上面剛說(shuō)的,交互一共有三種狀態(tài),按下、移動(dòng)、抬起,那么我們就先對(duì)這三種狀態(tài)進(jìn)行監(jiān)聽(tīng),

GestureDetector(
  child: CustomPaint(
    size: Size(size, size),
    painter:
        _GesturesUnlockPainter(_unlockController, centerOffset),
  ),
  onPanDown: (d) {
    // 手指按下
},
  onPanUpdate: (d) {
    // 移動(dòng)                
  },
  onPanEnd: (d) {
   // 抬起結(jié)束
  },
)

交互思路: 手勢(shì)密碼的特點(diǎn)是每個(gè)九宮格只允許點(diǎn)亮一次,再次經(jīng)過(guò)不保存數(shù)據(jù)。

按下: 判斷是否在九宮格內(nèi)部任一圓形區(qū)域內(nèi),在:點(diǎn)亮圓形,保存數(shù)據(jù),不在:不做任何操作,

移動(dòng): 判斷是否移動(dòng)到九宮格任一圓形區(qū)域內(nèi),在:判斷是否已點(diǎn)亮-未點(diǎn)亮:點(diǎn)亮圓形,保存數(shù)據(jù),已點(diǎn)亮:不做任何操作,不在區(qū)域內(nèi),也不做數(shù)據(jù)任何操作。

抬起: 獲取密碼,進(jìn)行設(shè)置或驗(yàn)證。

大概思路還是比較清晰的,下面我們就對(duì)這些判斷條件進(jìn)行判斷。

代碼:

///手指按下、移動(dòng)觸發(fā)
void judgeZone(Offset src) {
  /// 循環(huán)所有的九宮格
  for (int i = 0; i < centerOffset.length; i++) {
    var srcTranslate = src.translate(-size / 2, -size / 2);
    // 判斷手指按的位置是否在九宮格圓形區(qū)域
    if (judgeCircleArea(srcTranslate, centerOffset[i].offset, 30)) {
      // 在 判斷是否已添加
      for (int j = 0; j < _unlockController.points.length; j++) {
        if (_unlockController.points[j] == centerOffset[i]) {
          // 已添加過(guò) 返回
          return;
        }
      }
      // 未添加過(guò) 進(jìn)行添加
      _unlockController.addPoint(centerOffset[i]);
      return;
    }
  }
  // 無(wú)點(diǎn)
}
///判斷出是否在某點(diǎn)的半徑為r圓范圍內(nèi)
bool judgeCircleArea(Offset src, Offset dst, double r)=>(src - dst).distance <= r;

有了手指數(shù)據(jù)之后,我們就能根據(jù)這些數(shù)據(jù)的變化進(jìn)而通知畫(huà)布進(jìn)行更新了。

4、繪制、刷新密碼線

上面我們已經(jīng)拿到數(shù)據(jù)了,接下來(lái)我們進(jìn)行繪制密碼線,如何刷新畫(huà)布之前的文章我已經(jīng)講過(guò)很多遍了,這里不熟悉的同學(xué)可以看下之前繪制小海豚那一篇文章貝塞爾曲線繪制一個(gè)小海豚,回歸正題,既然我們拿到了手指經(jīng)過(guò)的九宮格的中心點(diǎn),那繪制線就變得非常容易了,

核心代碼:

var offsets = unlockController.points.map((e) => e.offset).toList();
// 繪制按壓點(diǎn)
canvas.drawPoints(
    PointMode.points,
    offsets,
    paint
      ..strokeWidth = 20
      ..strokeCap = StrokeCap.round
      ..color = Colors.red);
// 繪制密碼
Path path = Path();
if (unlockController.points.isNotEmpty) {
  path.moveTo(unlockController.points[0].offset.dx,
      unlockController.points[0].offset.dy);
  if (unlockController.currentOffset != null) {
  // 繪制當(dāng)前手勢(shì)線 未經(jīng)過(guò)九宮格圓形時(shí)
    canvas.drawLine(unlockController.points.last.offset,
        unlockController.currentOffset!, paint..strokeWidth = 2);
  }
}
for (int i = 1; i < unlockController.points.length; i++) {
  path.lineTo(unlockController.points[i].offset.dx,
      unlockController.points[i].offset.dy);
}
canvas.drawPath(path, paint..strokeWidth = 2);

這樣我們就把手勢(shì)經(jīng)過(guò)的密碼線繪制出來(lái)了。

效果圖:

5、加入密碼錯(cuò)誤動(dòng)畫(huà)

當(dāng)我們輸入密碼錯(cuò)誤時(shí),給用戶一個(gè)提示密碼錯(cuò)誤的交互也是很有必要的,那么接下來(lái)我們就添加一個(gè)簡(jiǎn)單文字抖動(dòng)效果提示用戶密碼輸入錯(cuò)誤。
添加動(dòng)畫(huà)也很簡(jiǎn)單,思路: 不斷改變文字的邊距從而達(dá)到抖動(dòng)效果。

核心代碼:

late AnimationController _animationController =
    AnimationController(vsync: this, duration: Duration(milliseconds: 500));

late CurvedAnimation curvedAnimation =
    CurvedAnimation(curve: Curves.easeIn, parent: _animationController);
late Animation<double> animation =
    Tween(begin: 0.0, end: 10.0).animate(curvedAnimation)
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          _animationController.reset();
        }
      });
AnimatedBuilder(
    animation: animation,
    builder: (ctx, child) {
      return Container(
        margin: EdgeInsetsDirectional.only(
            bottom: 20,
            start: _errorPwd() * 20,
            end: animation.value),
        child: Text(
          text,
          style: TextStyle(fontSize: 20, color: textColor),
        ),
      );
    }),
    
double _errorPwd() {
  double x = animation.value; // 變化速度 0-10,
  double d = x - x.truncate(); // 獲取這個(gè)數(shù)字的小數(shù)部分
  double? y;
  if (d <= 0.5) {
    y = 2 * d;
  } else {
    y = 1 - 2 * (d - 0.5);
  }
  return y;
}

假設(shè)我們?cè)O(shè)置的密碼是14789,也就是L型,看下最終效果:

完整源碼之后我會(huì)放到github上。

總結(jié)

通過(guò)手勢(shì)識(shí)別我們用到了App中核心的三大框架,手勢(shì)、繪制、以及動(dòng)畫(huà)中的知識(shí)。其實(shí)原理也并不復(fù)雜,只要掌握了這三大框架的核心基礎(chǔ)知識(shí)

到此這篇關(guān)于基于Flutter實(shí)現(xiàn)手勢(shì)密碼加密與解鎖功能的文章就介紹到這了,更多相關(guān)Flutter手勢(shì)密碼加密解鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android自定義相機(jī)聚焦和顯示框

    Android自定義相機(jī)聚焦和顯示框

    這篇文章主要為大家詳細(xì)介紹了Android自定義相機(jī)聚焦和顯示框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-01-01
  • android實(shí)現(xiàn)倒計(jì)時(shí)功能代碼

    android實(shí)現(xiàn)倒計(jì)時(shí)功能代碼

    實(shí)現(xiàn)倒計(jì)時(shí)每隔1秒,變換一下時(shí)間,截圖如下,感興趣的朋友想看下實(shí)現(xiàn)代碼,希望對(duì)你學(xué)習(xí)有所幫助
    2013-06-06
  • Android  TimerTask 的簡(jiǎn)單應(yīng)用及注意事項(xiàng)

    Android TimerTask 的簡(jiǎn)單應(yīng)用及注意事項(xiàng)

    這篇文章主要介紹了Android TimerTask 的簡(jiǎn)單應(yīng)用及注意事項(xiàng)的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • android WebView組件使用總結(jié)

    android WebView組件使用總結(jié)

    瀏覽器控件是每個(gè)開(kāi)發(fā)環(huán)境都具備的,這為馬甲神功提供了用武之地,windows的有webbrowser,android和ios都有webview;本篇主要介紹android的webview之強(qiáng)大,感興趣的朋友可以研究下
    2012-12-12
  • 詳解Android 基于TCP和UDP協(xié)議的Socket通信

    詳解Android 基于TCP和UDP協(xié)議的Socket通信

    這篇文章主要介紹了詳解Android 基于TCP和UDP協(xié)議的Socket通信,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11
  • 詳解關(guān)于Android Studio中安裝和gradle的一些坑

    詳解關(guān)于Android Studio中安裝和gradle的一些坑

    本篇文章主要介紹了關(guān)于Android Studio中安裝和gradle的一些坑,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • 快速掌握Android屏幕的知識(shí)點(diǎn)

    快速掌握Android屏幕的知識(shí)點(diǎn)

    相信不少設(shè)計(jì)師和工程師都被安卓設(shè)備紛繁的屏幕搞得暈頭轉(zhuǎn)向,我既做UI設(shè)計(jì),也做過(guò)一點(diǎn)安卓界面布局,剛好對(duì)這塊內(nèi)容比較熟悉,所以在此我將此部分知識(shí)重新梳理出來(lái)分享給大家!有需要的朋友們可以參考借鑒,下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2016-11-11
  • Android 初識(shí) Helloworld 詳解

    Android 初識(shí) Helloworld 詳解

    在Eclipse+ADT中創(chuàng)建HelloWorld非常簡(jiǎn)單,直接按照導(dǎo)航下一步就可以了。本文重點(diǎn)不在如何創(chuàng)建,而在理解HelloWorld項(xiàng)目的文件。需要的朋友可以參考下
    2013-07-07
  • android編程之XML文件解析方法詳解(附源碼)

    android編程之XML文件解析方法詳解(附源碼)

    這篇文章主要介紹了android編程之XML文件解析方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android解析XML文件的sax、pull及Dom三種方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • Android開(kāi)發(fā)之BroadcastReceiver用法實(shí)例分析

    Android開(kāi)發(fā)之BroadcastReceiver用法實(shí)例分析

    這篇文章主要介紹了Android開(kāi)發(fā)之BroadcastReceiver用法,實(shí)例分析了Android中廣播的相關(guān)使用技巧,需要的朋友可以參考下
    2015-05-05

最新評(píng)論