Flutter学习记录——19.手势和数据库缓存详情


在移动应用开发中,经常会使用到手势操作,这也是移动平台应用独有的一个功能特性。我们可以使用手势进行密码设置、通过手势操作进行定义一系列有含义的操作等等。Flutter 也支持手势操作的使用。
这节博客除了手势功能的用法外还会给大家讲解下 Flutter 中本地数据库的操作用法, Android 平台本地数据库一般是使用 SQLite,Flutter 通过插件的方式提供了本地数据库的相关操作方法。

1.手势的用法详解

Flutter 的手势控制包括:长按、点击、双击、拖拽、移动、缩放等等操作。这些手势操作都是通过 GestureDetector 来实现的。

我们看下 GestureDetector。GestureDetector 继承自 StatelessWidget,无状态组件。构造方法如下:

GestureDetector({
    Key key,
    // 子控件
    this.child,
    // 点击按下
    this.onTapDown,
    // 点击抬起
    this.onTapUp,
    // 点击
    this.onTap,
    // 触摸屏幕了,但是点击取消
    this.onTapCancel,
    // 双击
    this.onDoubleTap,
    // 长按
    this.onLongPress,
    // 长按开始
    this.onLongPressStart,
    this.onLongPressMoveUpdate,
    this.onLongPressUp,
    this.onLongPressEnd,
    // 垂直滑动拖拽按下
    this.onVerticalDragDown,
    // 垂直滑动拖拽开始
    this.onVerticalDragStart,
    this.onVerticalDragUpdate,
    // 垂直滑动拖拽结束
    this.onVerticalDragEnd,
    // 垂直滑动拖拽取消
    this.onVerticalDragCancel,
    // 水平滑动拖拽按下
    this.onHorizontalDragDown,
    this.onHorizontalDragStart,
    this.onHorizontalDragUpdate,
    this.onHorizontalDragEnd,
    this.onHorizontalDragCancel,
    this.onForcePressStart,
    this.onForcePressPeak,
    this.onForcePressUpdate,
    this.onForcePressEnd,
    // 手指按下
    this.onPanDown,
    // 按下移动开始
    this.onPanStart,
    // 手指按下开始滑动
    this.onPanUpdate,
    // 手指抬起
    this.onPanEnd,
    // 滑动取消
    this.onPanCancel,
    // 缩放开始
    this.onScaleStart,
    // 缩放滑动中
    this.onScaleUpdate,
    // 缩放结束
    this.onScaleEnd,
    this.behavior,
    this.excludeFromSemantics = false,
    this.dragStartBehavior = DragStartBehavior.start,
  })

接下来我们看下 GestureDetector 中几个常用的、重要的方法的用法:

// 首先看下最常用的点击、双击、长按事件
var gestureStatus = 'Gesture';
...
Center(
      child: GestureDetector(
        child: RaisedButton(
          child: Text(gestureStatus),
        ),
        // 点击
        onTap: () {
          setState(() {
            gestureStatus = 'onTap';
          });
        },
        // 双击
        onDoubleTap: () {
          setState(() {
            gestureStatus = 'onDoubleTap';
          });
        },
        // 长按
        onLongPress: () {
          setState(() {
            gestureStatus = 'onLongPress';
          });
        },
      ),
    )

我们只需要在要添加手势控制的 Widget 的外面包装一个 GestureDetector 即可,是不是很简单?

接下来再看一下 GestureDetector 实现横向或者纵向滑动的手势监听:

// 类似于我们使用纵向滚动条时,向下滑动查看内容的操作手势
// Flutter支持沿某一个方向的监听控制,我们先看下垂直方向监听

class GestureSamplesState extends State<GestureSamples> {
  var gestureStatus = 'Gesture';
  var _top = 100.0;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return getstureVertical(context);
  }

  Widget getstureVertical(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Gesture'),
      ),
      body: Container(
          child: Stack(
        children: <Widget>[
          Positioned(
            top: _top,
            left: 100.0,
            child: GestureDetector(
                child: Icon(Icons.history),
                //垂直方向拖动监听
                onVerticalDragUpdate: (DragUpdateDetails details) {
                  setState(() {
                      // 动态更新垂直坐标
                    _top += details.delta.dy;
                  });
                }),
          )
        ],
      )),
    );
  }

}

效果图如下:

纵向滚动监听效果图

同理,水平监听滚动也是同样的用法。如果一个组件既有水平拖拽监听又有垂直拖拽监听的话,执行哪个方向的主要取决于你在哪个方向上的位移大。

再看下 Flutter GestureDetector 实现缩放操作:

class GestureSamplesState extends State<GestureSamples> {
  var gestureStatus = 'Gesture';

  var _width = 180.0;
  var _scale = 1.0;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return getstureScale(context);
  }

  Widget getstureScale(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Gesture'),
      ),
      body: Container(
          child: Stack(
        children: <Widget>[
          Center(
            child: GestureDetector(
              // 动态控制宽度,高度自适应
              child: Image.asset(
                "assets/image_appbar.jpg",
                width: _width,
              ),
              onScaleStart: (ScaleStartDetails details) {
                print('onScaleStart:$details.focalPoint');
              },
              onScaleEnd: (ScaleEndDetails details) {
                print('onScaleEnd:$details.focalPoint');
              },
              onScaleUpdate: (ScaleUpdateDetails details) {
                setState(() {
                  // 除了缩放也可以进行旋转操作
                  // details.rotation.clamp(0, 360);
                  // 缩放倍数在0.5到5倍之间
                  _scale = details.scale.clamp(0.5, 5);
                  _width = 180 * _scale;
                });
              },
            ),
          )
        ],
      )),
    );
  }

}

效果图如下:

缩放监听效果图

接下来看下 GestureDetector 实现移动拖拽操作:

class GestureSamplesState extends State<GestureSamples> {
  var gestureStatus = 'Gesture';
  var _top = 100.0;
  var _left = 100.0;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return getstureMove(context);
  }

  Widget getstureMove(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Gesture'),
      ),
      body: Container(
          child: Stack(
        children: <Widget>[
          Positioned(
            top: _top,
            left: _left,
            child: GestureDetector(
              child: Icon(Icons.home),
              //手指按下时
              onPanDown: (DragDownDetails e) {
                //手指按下的位置
                print("按下位置:${e.globalPosition}");
              },
              //手指滑动时
              onPanUpdate: (DragUpdateDetails e) {
                //手指滑动时,更新偏移,重新构建
                setState(() {
                  _top += e.delta.dy;
                  _left += e.delta.dx;
                });
              },
              // 手指抬起时
              onPanEnd: (DragEndDetails e) {
                //滑动结束时在x轴、y轴上的速度
                print("结束时速度:${e.velocity}");
              },
            ),
          )],
      )),
    );
  }

}

效果图如下:

缩放监听效果图

扩展内容:

针对手势监听大家也可以自学了解下 Listener 用法、GestureRecognizer 用法、RawGestureDetector
用法。可以对比着进行扩展学习。

2.数据库的用法详解

Flutter 原生 API 是不支持数据库操作的,目前是以插件库方式进行数据库操作。Flutter 官方提供了一个官方插件库:sqflite,实现了数据库的增删改查操作。

插件库地址:https://pub.dev/packages/sqflite

首先需要在 pubspec.yaml 里添加依赖:

dependencies:
  sqflite: ^1.1.5

在使用的地方导入:

import 'package:sqflite/sqflite.dart';

接下来看下具体用法,首先我们要建立一个数据库表实体类,这里举例为 Note 类:

final String tableName = 'notes';// 表名
final String columnId = '_id';// 属性名
final String columnTitle = 'title';// 属性名
final String columnContent = 'content';// 属性名

// 实体类
class Note {
  int id;
  String title;
  String content;

  // 将实体对象类转为数据集合
  Map<String, dynamic> toMap() {
    var map = <String, dynamic>{
      columnTitle: title,
      columnContent: content,
    };
    if (id != null) {
      map[columnId] = id;
    }
    return map;
  }

  // 构造方法/实例化方法
  Note();

  // 通过数据集合返回一个实体对象
  Note.fromMap(Map<String, dynamic> map) {
    id = map[columnId];
    title = map[columnTitle];
    content = map[columnContent];
  }
}

接下来创建数据库表的操作工具类:

import 'package:sqflite/sqflite.dart';

import 'Note.dart';

// 数据库操作工具类
class NoteDbHelper {
  Database db;

  Future open(String path) async {
    // 打开/创建数据库
    db = await openDatabase(path, version: 1,
        onCreate: (Database db, int version) async {
      await db.execute('''
create table Notes ( 
  _id integer primary key autoincrement, 
  title text not null,
  content text not null)
''');
    });
  }

  Database getDatabase(){
    return db;
  }

  // 增加一条数据
  Future<Note> insert(Note note) async {
    note.id = await db.insert("notes", note.toMap());
    return note;
  }

  // 通过ID查询一条数据
  Future<Note> getNoteById(int id) async {
    List<Map> maps = await db.query('notes',
        columns: [columnId, columnTitle, columnContent],
        where: '_id = ?',
        whereArgs: [id]);
    if (maps.length > 0) {
      return Note.fromMap(maps.first);
    }
    return null;
  }

  // 通过ID删除一条数据
  Future<int> deleteById(int id) async {
    return await db.delete('notes', where: '_id = ?', whereArgs: [id]);
  }

  // 更新数据
  Future<int> update(Note note) async {
    return await db.update('notes', note.toMap(),
        where: '_id = ?', whereArgs: [note.id]);
  }

  // 关闭数据库
  Future close() async => db.close();
}

最后我们看下如何调用使用:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_samples/samples/note_db_helpter.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

import 'Note.dart';

...

class SQLiteSamplesState extends State<SQLiteSamples> {
  NoteDbHelper noteDbHelpter;

  @override
  void initState() {
    super.initState();
    noteDbHelpter = NoteDbHelper();
    String databasesPath = getDatabasesPath().toString();
    String path = join(databasesPath, 'notesDb.db');
    noteDbHelpter.open(path);

    noteDbHelpter.getNoteById(1).then((Note note) {
      print(note.title);
    });

    // 也可以这样使用
    noteDbHelpter
        .getDatabase()
        .query('notes')
        .then((List<Map<String, dynamic>> records) {
      Map<String, dynamic> mapRead = records.first;
      // 读取属性值
      mapRead['title'] = '1';
      // 如果想修改的话
      Map<String, dynamic> map = Map<String, dynamic>.from(mapRead);
      // 更新修改
      map['title'] = '2';
    });

    // 支持原始SQL语句使用
    noteDbHelpter.getDatabase().rawUpdate(
        'UPDATE notes SET title = ?, content = ? WHERE _id = ?',
        ['my title', 'my content', 2]).then((int count) {
      print('updated: $count');
    });
  }

}

sqflite 同样也支持事物操作和批量操作。

// 事务操作
await db.transaction((txn) async {
  await txn.execute('CREATE TABLE Test1 (id INTEGER PRIMARY KEY)');
  ...
});

// 批量操作
batch = db.batch();
batch.insert('Test', {'name': 'item'});
batch.update('Test', {'name': 'new_item'}, where: 'name = ?', whereArgs: ['item']);
batch.delete('Test', where: 'name = ?', whereArgs: ['item']);
results = await batch.commit();

sqflite 支持如下数据类型:

  • INTEGER(对应 int)
  • REAL(对应 num)
  • TEXT(对应 String)
  • BLOB(对应 Uint8List)。

3.总结

本节博客主要是给大家讲解了 Flutter 的手势和数据库的用法,数据库的使用我们要重点掌握。主要注意点和建议如下:

  • 重点掌握数据库增删改查的用法;
  • 使用 GestureDetector 进行实践操作一下。
发布了253 篇原创文章 · 获赞 52 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41151659/article/details/103400273