您的位置 首页 > 腾讯云社区

Flutter:使用手势识别做一个360旋转展物---kimihe

最近在复习Flutter的GestureDetector相关知识时,想到了以前用Android实现的展物项目,这次完整的用Flutter实现了一下,真是感觉代码简洁了很多,

项目整体需求进入app时展物自动顺时针旋转触摸展物时停止旋转手势在展物上左右触摸滑动时展物跟随旋转离开触摸时记录触摸方向然后继续自动旋转可以顺时针,也可以逆时针旋转旋转的原理

首先我们了解一下怎么让展物旋转起来,展物是一件在博物馆展示的文物,一共拍摄了72张,角度每5度进行一次拍摄,所以总体算起来就是72乘以5,一共就是360度正好是一圈,那么写到代码里面就是从第1张图开始计算,然后每90毫秒替换一张,不断累加到第72张,然后再从第一张开始,这样就正好转了一圈。 理解了实现思路之后,那么,转换成Flutter代码如下: 先设定第一张图片,

Image.asset( 'images/product00${index}.png', fit: BoxFit.cover, width: width, height: height, ), 复制代码

然后,我们通过Timer每100秒替换一下index改变图片的值,代码如下:

Timer.periodic(new Duration(milliseconds: 90), (timer) { setState(() {}); if (index < count) { index++; return; } // 重新回到第一张图 index = 1; }); 复制代码

记得Timer在用完之后需要cancel掉,大家对state应该有所了解,这里就是通过修改 index的值得替换图片的。

但是这样会有一个问题,就是图片替换太快,而每张图片大小在40K左右,替换过程中会有白屏闪烁的问题,这是因为图片需要载入到内存中然后通过Image.asset展示出来,幸好,有一个属性可以解决这样的问题,把gaplessPlayback设置为true即可, 修改后代码如下:

Image.asset( 'images/product00${index}.png', fit: BoxFit.cover, width: width, height: height, // 该属性防止图片快速切换时白屏发生,在新图出现前保持旧的图 gaplessPlayback: true, excludeFromSemantics: true, ), 复制代码

gaplessPlayback设置为true就能确保在新图出现之前呈现的还是旧图,这样就不会出现白屏闪烁问题。

GestureDetector基本使用

接下来就是如何与手势结合起来了,通过一个例子,我们先来了解一下GestureDetector的基本用法,代码如下:

import 'package:flutter/material.dart'; class GestureDetectorPage extends StatefulWidget { @override _GestureDetectorState createState() => new _GestureDetectorState(); } class _GestureDetectorState extends State<GestureDetectorPage> { String _opName = "未检测到操作"; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("GestureDetector手势识别"), ), body: Center( child: GestureDetector( child: Container( alignment: Alignment.center, color: Colors.blue, width: 240.0, height: 120.0, child: Text( _opName, style: TextStyle(color: Colors.white), ), ), onTap: () => _showEventText("Tap"), onTapUp: (e) => _showEventText("TapUp"), onTapDown: (e) => _showEventText("TapDown"), onTapCancel: () => _showEventText("TapCancel"), onDoubleTap: () => _showEventText("DoubleTap"), onLongPress: () => _showEventText("LongPress"), onVerticalDragDown: (e) => _showEventText("onVerticalDragDown"), onVerticalDragStart: (e) => _showEventText("onVerticalDragStart"), onVerticalDragUpdate: (e) => _showEventText("onVerticalDragUpdate"), onVerticalDragEnd: (e) => _showEventText("onVerticalDragEnd"), onVerticalDragCancel: () => _showEventText("onVerticalDragCancel"), onHorizontalDragDown: (e) => _showEventText("onHorizontalDragDown"), onHorizontalDragStart: (e) => _showEventText("onHorizontalDragStart"), onHorizontalDragUpdate: (e) => _showEventText("onHorizontalDragUpdate"), onHorizontalDragEnd: (e) => _showEventText("onHorizontalDragEnd"), onHorizontalDragCancel: () => _showEventText("onHorizontalDragCancel"), // onPanDown: (e) => _showEventText("onPanDown"), // onPanStart: (e) => _showEventText("onPanStart"), // onPanUpdate: (e) => _showEventText("onPanUpdate"), // onPanEnd: (e) => _showEventText("onPanEnd"), // onScaleStart: (e) => _showEventText("onScaleStart"), // onScaleUpdate: (e) => _showEventText("onScaleUpdate"), // onScaleEnd: (e) => _showEventText("onScaleEnd"), ), ), ); } void _showEventText(String text) { setState(() { _opName = text; }); print(_opName); } } 复制代码

通过这个例子,我们可以在屏幕上的Text区域记录并显示出经过GestureDetector手势事件,以便帮助我们理解。

在本例中,我们需要用到的就是onTap,onPanStart,onPanUpdate,onPanEnd这几个回调方法,经过实践并对代码加入手势事件之后,代码如下:

GestureDetector( onTap: () => _cancelTimer(), onPanStart: (e) => _cancelTimer(), onPanUpdate: (e) => _onTouchImage(e), // 在触屏结束之后,恢复自动旋转 onPanEnd: (e) => _startTimer(), child: Image.asset( 'images/product00${index}.png', fit: BoxFit.cover, width: width, height: height, // 该属性防止图片快速切换时白屏发生,在新图出前时保持旧的图 gaplessPlayback: true, excludeFromSemantics: true, ), ) 复制代码

其中onTap,onPanStart,onPanEnd这几个很好理解,主要是onPanUpdate,里面调用了一个自己实现的_onTouchImage(e)方法,代码如下:

void _onTouchImage(e) { setState(() { index -= e.delta.dx.toInt(); }); // 防止取到不存在的图片报错 if (index < 1) index = 1; if (index > count) index = count; } 复制代码

上面的代码中,在触摸屏幕的同时转换成index值替换图片,这样就实现了图片替换跟随手势的功能,然后,在手指离开屏幕之后还能继续旋转,这时候我们可以在触摸时加入方向判断,

if (e.delta.dx < 0) { // 顺时针 direction = DIRECTION_CLOCKWISE; } if (e.delta.dx > 0) { // 逆时针 direction = DIRECTION_ANTICLOCKWISE; } 复制代码

这样,一个简单的360展物就实现了,你可以在屏幕上任意触摸控制展物,很神奇吧!看一下最终效果:

github地址:github.com/heruijun/fl…

---来自腾讯云社区的---kimihe

关于作者: 瞎采新闻

这里可以显示个人介绍!这里可以显示个人介绍!

热门文章

留言与评论(共有 0 条评论)
   
验证码: