gpt4 book ai didi

dart - Flutter - ListView更新后拖动动画未返回开始

转载 作者:行者123 更新时间:2023-12-03 04:30:12 27 4
gpt4 key购买 nike

ListView的动画关于向左拖动和删除按钮出现的项目工作正常。问题是如果我让删除按钮出现并更改页面,当我返回 pop()到上一页按钮不断出现。

动画没有回到开头。如果我更新 ListView 中的项目,也会发生同样的情况。 ,例如删除项目。该项目已删除,但动画未删除。

看来我正在更新 ListView内容而不是 ListView本身。

你怎么能解决这个问题?

我试图摧毁ListView每次更新其项目,但我没有得到它。我也不知道这是否是解决问题的正确方法。
ListView通过 buildTile() 构建函数及其项来自数据库。

下面我放了代码和一个 gif 来演示问题所在。

要使用下面的代码,您需要插入 sqflitepath_provider依赖于 pubspec.yaml , 因此:

dependencies:
sqflite: any
path_provider: any
flutter:
sdk: flutter

enter image description here
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:ui' as ui;

enum DialogOptionsAction {
cancel,
ok
}

void main() {
runApp(new MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
routes: <String, WidgetBuilder> {
'/newpage': (BuildContext context) => new NewPage(),
},
);
}
}

class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
DatabaseClient _db = new DatabaseClient();
List listCategory = [];
List<Widget> tiles;

List colors = [
const Color(0xFFFFA500),
const Color(0xFF279605),
const Color(0xFF005959)
];

createdb() async {
await _db.create().then(
(data){
_db.getAllCategory().then((list){
setState(() {
this.listCategory = list;
});
});
}
);
}

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

void showCategoryDelete<T>({ BuildContext context, Widget child }) {
showDialog<T>(
context: context,
child: child,
)
.then<Null>((T value) {
if (value != null) {
setState(() { print(value); });
}
});
}

@override
Widget build(BuildContext context) {
List<Widget> buildTile(List list) {
this.tiles = [];
for(var dict in list) {
this.tiles.add(
new ItemCategory(
id: dict['id'],
category: dict['name'],
color: this.colors[dict['color']],
onPressed: () async {
showCategoryDelete<DialogOptionsAction>(
context: context,
child: new AlertDialog(
title: const Text('Delete Category'),
content: new Text(
'Do you want to delete this category?',
style: new TextStyle(
color: Colors.black26,
fontSize: 16.0,
fontFamily: "Roboto",
fontWeight: FontWeight.w500,
)
),
actions: <Widget>[
new FlatButton(
child: const Text('CANCEL'),
onPressed: () {
Navigator.pop(context);
}
),
new FlatButton(
child: const Text('OK'),
onPressed: () {
_db.deleteCategory(dict['id']).then(
(list) {
setState(() {
this.listCategory = list;
});
}
);
Navigator.pop(context);
}
)
]
)
);
},
)
);
}
return this.tiles;
}
return new Scaffold(
appBar: new AppBar(
title: new Text('Categories'),
actions: <Widget>[
new IconButton(
icon: const Icon(Icons.add),
color: new Color(0xFFFFFFFF),
onPressed: () async {
await Navigator.of(context).pushNamed('/newpage').then(
(data){
_db.getAllCategory().then((list){
setState(() {
this.listCategory = list;
});
});
}
);
}
)
],
),
body: new ListView(
padding: new EdgeInsets.only(top: 8.0, right: 0.0, left: 0.0),
children: buildTile(this.listCategory)
)
);
}
}

class NewPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('New Page'),
),
);
}
}

//Creating Database with some data and two queries
class DatabaseClient {
Database db;

Future create() async {
Directory path = await getApplicationDocumentsDirectory();
String dbPath = join(path.path, "database.db");
db = await openDatabase(dbPath, version: 1, onCreate: this._create);
}

Future _create(Database db, int version) async {
await db.execute("""
CREATE TABLE category (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
color INTEGER NOT NULL
)""");
await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo1', 0)");
await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo2', 1)");
await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo3', 2)");
}

Future getAllCategory() async {
Directory path = await getApplicationDocumentsDirectory();
String dbPath = join(path.path, "database.db");
Database db = await openDatabase(dbPath);

List list = await db.rawQuery('SELECT * FROM category');
await db.close();

return list;
}

Future deleteCategory(int id) async {
Directory path = await getApplicationDocumentsDirectory();
String dbPath = join(path.path, "database.db");
Database db = await openDatabase(dbPath);

await db.delete('category', where: "id = ?", whereArgs: [id]);
List list = await db.rawQuery('SELECT * FROM category');

await db.close();

return list;
}
}

//Creating ListViews items
class ItemCategory extends StatefulWidget {
ItemCategory({ Key key, this.id, this.category, this.color, this.onPressed}) : super(key: key);

final int id;
final String category;
final Color color;
final VoidCallback onPressed;

@override
ItemCategoryState createState() => new ItemCategoryState();
}

class ItemCategoryState extends State<ItemCategory> with TickerProviderStateMixin {
ItemCategoryState();

DatabaseClient db = new DatabaseClient();
AnimationController _controller;
Animation<double> _animation;
double flingOpening;
bool startFling = true;

void initState() {
super.initState();
_controller = new AnimationController(duration:
const Duration(milliseconds: 246), vsync: this);

_animation = new CurvedAnimation(
parent: _controller,
curve: new Interval(0.0, 1.0, curve: Curves.linear),
);
}

void _move(DragUpdateDetails details) {
final double delta = details.primaryDelta / 304;
_controller.value -= delta;
}

void _settle(DragEndDetails details) {
if(this.startFling) {
_controller.fling(velocity: 1.0);
this.startFling = false;
} else if(!this.startFling){
_controller.fling(velocity: -1.0);
this.startFling = true;
}
}

@override
Widget build(BuildContext context) {
final ui.Size logicalSize = MediaQuery.of(context).size;
final double _width = logicalSize.width;
this.flingOpening = -(48.0/_width);

return new GestureDetector(
onHorizontalDragUpdate: _move,
onHorizontalDragEnd: _settle,
child: new Stack(
children: <Widget>[
new Positioned.fill(
child: new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new Container(
decoration: new BoxDecoration(
color: new Color(0xFFE57373),
),
child: new IconButton(
icon: new Icon(Icons.delete),
color: new Color(0xFFFFFFFF),
onPressed: widget.onPressed
)
),
],
),
),
new SlideTransition(
position: new Tween<Offset>(
begin: Offset.zero,
end: new Offset(this.flingOpening, 0.0),
).animate(_animation),
child: new Container(
decoration: new BoxDecoration(
border: new Border(
top: new BorderSide(style: BorderStyle.solid, color: Colors.black26),
),
color: new Color(0xFFFFFFFF),
),
margin: new EdgeInsets.only(top: 0.0, bottom: 0.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Expanded(
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Container(
margin: new EdgeInsets.only(left: 16.0),
padding: new EdgeInsets.only(right: 40.0, top: 4.5, bottom: 4.5),
child: new Row(
children: <Widget>[
new Container(
margin: new EdgeInsets.only(right: 16.0),
child: new Icon(
Icons.brightness_1,
color: widget.color,
size: 35.0,
),
),
new Text(
widget.category,
style: new TextStyle(
color: Colors.black87,
fontSize: 14.0,
fontFamily: "Roboto",
fontWeight: FontWeight.w500,
),
),
],
)
)
],
),
)
],
),
)
),
],
)
);
}
}

最佳答案

根据Flutter - Widget animation status remains even after it has been removed

只需将 key 插入新的 ItemCategory (

我需要通过 key给 children 。否则渲染器将无法知道哪个 SlideTransition 被删除,并使用索引。

...
@override
Widget build(BuildContext context) {
List<Widget> buildTile(List list) {
this.tiles = [];
for(var dict in list) {
this.tiles.add(
new ItemCategory(
key: new Key(dict), //new
id: dict['id'],
category: dict['name'],
...

enter image description here

完整的代码是:
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:ui' as ui;

enum DialogOptionsAction {
cancel,
ok
}

void main() {
runApp(new MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
routes: <String, WidgetBuilder> {
'/newpage': (BuildContext context) => new NewPage(),
},
);
}
}

class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
DatabaseClient _db = new DatabaseClient();
List listCategory = [];
List<Widget> tiles;

List colors = [
const Color(0xFFFFA500),
const Color(0xFF279605),
const Color(0xFF005959)
];

createdb() async {
await _db.create().then(
(data){
_db.getAllCategory().then((list){
setState(() {
this.listCategory = list;
});
});
}
);
}

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

void showCategoryDelete<T>({ BuildContext context, Widget child }) {
showDialog<T>(
context: context,
child: child,
)
.then<Null>((T value) {
if (value != null) {
setState(() { print(value); });
}
});
}

@override
Widget build(BuildContext context) {
List<Widget> buildTile(List list) {
this.tiles = [];
for(var dict in list) {
this.tiles.add(
new ItemCategory(
key: new Key(dict), //new
id: dict['id'],
category: dict['name'],
color: this.colors[dict['color']],
onPressed: () async {
showCategoryDelete<DialogOptionsAction>(
context: context,
child: new AlertDialog(
title: const Text('Delete Category'),
content: new Text(
'Do you want to delete this category?',
style: new TextStyle(
color: Colors.black26,
fontSize: 16.0,
fontFamily: "Roboto",
fontWeight: FontWeight.w500,
)
),
actions: <Widget>[
new FlatButton(
child: const Text('CANCEL'),
onPressed: () {
Navigator.pop(context);
}
),
new FlatButton(
child: const Text('OK'),
onPressed: () {
_db.deleteCategory(dict['id']).then(
(list) {
setState(() {
this.listCategory = list;
});
}
);
Navigator.pop(context);
}
)
]
)
);
},
)
);
}
return this.tiles;
}
return new Scaffold(
appBar: new AppBar(
title: new Text('Categories'),
actions: <Widget>[
new IconButton(
icon: const Icon(Icons.add),
color: new Color(0xFFFFFFFF),
onPressed: () async {
await Navigator.of(context).pushNamed('/newpage').then(
(data){
_db.getAllCategory().then((list){
setState(() {
this.listCategory = list;
});
});
}
);
}
)
],
),
body: new ListView(
padding: new EdgeInsets.only(top: 8.0, right: 0.0, left: 0.0),
children: buildTile(this.listCategory)
)
);
}
}

class NewPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('New Page'),
),
);
}
}

//Creating Database with some data and two queries
class DatabaseClient {
Database db;

Future create() async {
Directory path = await getApplicationDocumentsDirectory();
String dbPath = join(path.path, "database.db");
db = await openDatabase(dbPath, version: 1, onCreate: this._create);
}

Future _create(Database db, int version) async {
await db.execute("""
CREATE TABLE category (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
color INTEGER NOT NULL
)""");
await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo1', 0)");
await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo2', 1)");
await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo3', 2)");
}

Future getAllCategory() async {
Directory path = await getApplicationDocumentsDirectory();
String dbPath = join(path.path, "database.db");
Database db = await openDatabase(dbPath);

List list = await db.rawQuery('SELECT * FROM category');
await db.close();

return list;
}

Future deleteCategory(int id) async {
Directory path = await getApplicationDocumentsDirectory();
String dbPath = join(path.path, "database.db");
Database db = await openDatabase(dbPath);

await db.delete('category', where: "id = ?", whereArgs: [id]);
List list = await db.rawQuery('SELECT * FROM category');

await db.close();

return list;
}
}

//Creating ListViews items
class ItemCategory extends StatefulWidget {
ItemCategory({ Key key, this.id, this.category, this.color, this.onPressed}) : super(key: key);

final int id;
final String category;
final Color color;
final VoidCallback onPressed;

@override
ItemCategoryState createState() => new ItemCategoryState();
}

class ItemCategoryState extends State<ItemCategory> with TickerProviderStateMixin {
ItemCategoryState();

DatabaseClient db = new DatabaseClient();
AnimationController _controller;
Animation<double> _animation;
double flingOpening;
bool startFling = true;

void initState() {
super.initState();
_controller = new AnimationController(duration:
const Duration(milliseconds: 246), vsync: this);

_animation = new CurvedAnimation(
parent: _controller,
curve: new Interval(0.0, 1.0, curve: Curves.linear),
);
}

void _move(DragUpdateDetails details) {
final double delta = details.primaryDelta / 304;
_controller.value -= delta;
}

void _settle(DragEndDetails details) {
if(this.startFling) {
_controller.fling(velocity: 1.0);
this.startFling = false;
} else if(!this.startFling){
_controller.fling(velocity: -1.0);
this.startFling = true;
}
}

@override
Widget build(BuildContext context) {
final ui.Size logicalSize = MediaQuery.of(context).size;
final double _width = logicalSize.width;
this.flingOpening = -(48.0/_width);

return new GestureDetector(
onHorizontalDragUpdate: _move,
onHorizontalDragEnd: _settle,
child: new Stack(
children: <Widget>[
new Positioned.fill(
child: new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new Container(
decoration: new BoxDecoration(
color: new Color(0xFFE57373),
),
child: new IconButton(
icon: new Icon(Icons.delete),
color: new Color(0xFFFFFFFF),
onPressed: widget.onPressed
)
),
],
),
),
new SlideTransition(
position: new Tween<Offset>(
begin: Offset.zero,
end: new Offset(this.flingOpening, 0.0),
).animate(_animation),
child: new Container(
decoration: new BoxDecoration(
border: new Border(
top: new BorderSide(style: BorderStyle.solid, color: Colors.black26),
),
color: new Color(0xFFFFFFFF),
),
margin: new EdgeInsets.only(top: 0.0, bottom: 0.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Expanded(
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Container(
margin: new EdgeInsets.only(left: 16.0),
padding: new EdgeInsets.only(right: 40.0, top: 4.5, bottom: 4.5),
child: new Row(
children: <Widget>[
new Container(
margin: new EdgeInsets.only(right: 16.0),
child: new Icon(
Icons.brightness_1,
color: widget.color,
size: 35.0,
),
),
new Text(
widget.category,
style: new TextStyle(
color: Colors.black87,
fontSize: 14.0,
fontFamily: "Roboto",
fontWeight: FontWeight.w500,
),
),
],
)
)
],
),
)
],
),
)
),
],
)
);
}
}

关于dart - Flutter - ListView更新后拖动动画未返回开始,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47265564/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com