开启Fluter基础之旅<五>-------ListView 3D滚动、Flipper效果、ListView下拉刷新&上拉加载、ListView重排序...

继续来来操练Flutter的基础,对于Flutter的学习也有一段时间了,实操项目还木有做过,所以待这次基础学完之后就打算用一个项目对之前所学的进行一下巩固,不然光学这些零散的知识点最终还是不会Flutter。

3D效果:

效果:

有点类似于翻书的效果,不过没有翻书那么立体。 

具体实现:

首先绘制一个正方形:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter ListView之3d示例'),
      ),
      body: Center(
        child: Container(
          color: Colors.red,
          width: 200.0,
          height: 200.0,
        ),
      ),
    );
  }
}

给正方形加上手势:

关于手势这块在上一次https://www.cnblogs.com/webor2006/p/12649906.html已经学习过了,这里就不过多的解释了:

然后加一个手势,我们应该是要能得到当前触摸的坐标点,这里可以用这个命令参数:

了解一下这个参数:

啥意思?也就是对于在屏幕中移动的点也能监听到,不管是垂直还是水平还着其它方向的,这里咱们可以定义一个坐标点,然后每次这个手势触发时进行坐标点的更新,如下:

然后再加一个双击的事件将其坐标点还原:

实现3D效果:

然后这里给加一个根据手指的位置来进行移动的动画,就是Transform,这个在之前平移时也已经学习过了:

运行瞅一下:

抽风了一样,旋转得太快了,我们将旋转的幅度变小一点再看下:

再运行:

但是木有3D的视角,接下来将其变为3D视角:

最终的效果就如开始所演示的那样了。

Flipper效果:

效果:

 

具体实现:

1、画两个矩形:

这里用Card来定义一下,这个卡片组件在之前https://www.cnblogs.com/webor2006/p/12578218.html已经学习过了,直接开撸:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  Offset _offset = Offset.zero;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Flipper_widget示例'),
      ),
      body: Card1(),
    );
  }
}

class Card1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Card(
      color: Colors.red,
      child: Container(
          width: 200.0,
          height: 200.0,
          child: Center(
            child: Text(
              '点我看密码',
              style: TextStyle(color: Colors.white, fontSize: 30.0),
            ),
          )),
    );
  }
}

运行:

校仿着再定义一个:

class Card2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Card(
      color: Colors.blue,
      child: Container(
          width: 200.0,
          height: 200.0,
          child: Center(
            child: Text(
              '123456',
              style: TextStyle(color: Colors.white, fontSize: 30.0),
            ),
          )),
    );
  }
}

2、将其用IndexedStack包装起来:

那这两个控件需要重叠起来,类似于Android的FrameLayout, 这块在之前https://www.cnblogs.com/webor2006/p/12578218.html也已经学习过了,下面来整合一下:

4、增加手势:

5、执行动画:

这里就是点击之后需要执行一下翻转的效果,关于动画这块就不多解释了,这里会涉及到AnimationController、Mixin的用法,可以参考博客https://www.cnblogs.com/webor2006/p/12649906.html,直接上代码:

接下来则需要将其应用到咱们的控件上,此时就需要使用AnimatedBuilder了,也是之前学习过的,不多说:

最终的效果就如之前所示了,稍稍麻烦一点,但是有之前的基础其实也容易理解,关于动画这块没有其它好办法,就得经常用才行。

ListView 3D滚动:ListWheelScrollView

效果:

还是比较拉风的

具体实现:

1、先使用一下ListWheelScrollView控件:

这里会用到ListWheelScrollView这个控件,先看一下它的简单使用:

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: HomePage(),
    ));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Flutter listview_3d示例'),
        ),
        body: Center(
          child: ListWheelScrollView(
            itemExtent:
                MediaQuery.of(context).size.height * 0.6, //item的高度占整个屏幕的6成
            children: List.generate(20, (i) => i)
                .map((m) => Text(
                      m.toString(),
                      style: TextStyle(fontSize: 30.0),
                    ))
                .toList(),
          ),
        ));
  }
}

运行:

其实也就是我们平常所看到的日历选择控件。

2、加入3d效果:

接下来改成3d图片的效果,先定义要加载的图片数据:

接下来具体的列表项则根据这个图片数据来生成:

class _HomePageState extends State<HomePage> {
  var images = [
    'assets/images/test.jpg',
    'assets/images/test.jpg',
    'assets/images/test.jpg',
    'assets/images/test.jpg',
    'assets/images/test.jpg',
    'assets/images/test.jpg',
    'assets/images/test.jpg',
    'assets/images/test.jpg',
    'assets/images/test.jpg',
    'assets/images/test.jpg',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Flutter listview_3d示例'),
        ),
        body: Center(
          child: ListWheelScrollView(
            perspective: 0.003,
            diameterRatio: 2.0, //直径比
            itemExtent:
                MediaQuery.of(context).size.height * 0.6, //item的高度占整个屏幕的6成
            children: images
                .map((m) => Card(
                      clipBehavior: Clip.antiAlias,
                      shape: RoundedRectangleBorder(
                          //设置圆角
                          borderRadius: BorderRadius.circular(20.0)),
                      child: Stack(
                        fit: StackFit.expand,
                        alignment: Alignment.center,
                        children: <Widget>[
                          Image.asset(
                            m,
                            fit: BoxFit.cover,
                          ),
                          Positioned(
                            bottom: 30.0,
                            left: 30.0,
                            child: Text(
                              'test',
                              style: TextStyle(
                                  color: Colors.white, fontSize: 30.0),
                            ),
                          )
                        ],
                      ),
                    ))
                .toList(),
          ),
        ));
  }
}

其效果就如开头所演示的。

ListView下拉刷新&上拉加载: 

对于这样的效果应该都非常之熟悉了,也是实际项目中必须要用到的,所以来看一下在Flutter中是如何来实现的。

效果:

具体实现:

1、生成列表数据

import 'dart:math';

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: HomePage(),
    ));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  List list = new List();

  @override
  void initState() {
    super.initState();
    list = List.generate(Random().nextInt(20) + 15, (i) => 'Item $i');
  }

  Future<void> _refresh() {
    //TODO 下拉刷新逻辑
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Flutter 下拉刷新、上拉加载示例'),
        ),
        body: Center(
          child: RefreshIndicator(
            child: ListView.builder(
                itemCount: list?.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text(list[index]),
                  );
                }),
            onRefresh: _refresh,
          ),
        ));
  }
}

运行:

目前它就具有上拉刷新的效果了,但是我们还木有编写上拉刷新的功能,下面来实现一下。

2、实现上拉刷新:

这里就需要使用async和await来模拟异步请求了,关于async和await的知识点可以参考:https://www.cnblogs.com/webor2006/p/11994645.html, 为了看到效果这里做一个延时:

看一下效果:

另外对于下拉刷新的距离可以进行控制,如下:

默认它是40:

然后为了模拟进来列表的数据是从后台加载的,照理应该有一个loading等待的过程,所以这里可以这样改一下子:

class _HomePageState extends State<HomePage> {
  List list = new List();

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

  Future<void> _refresh() async {
    await Future.delayed(Duration(seconds: 3), () {
      setState(() {
        list =
            List.generate(Random().nextInt(20) + 15, (i) => 'refresh Item $i');
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Flutter 下拉刷新、上拉加载示例'),
        ),
        body: Center(
          child: RefreshIndicator(
              displacement: 20,
              child: list == null || list.isEmpty
                  ? Center(
                      //如果为null则增加一个loading效果
                      child: CircularProgressIndicator(),
                    )
                  : ListView.builder(
                      itemCount: list?.length,
                      itemBuilder: (context, index) {
                        return ListTile(
                          title: Text(list[index]),
                        );
                      }),
              onRefresh: _refresh),
        ));
  }
}

运行:

3、实现下拉加载更多:

接下来则来实现一下分页加载的效果,对于分页加载RefreshIndicator就木有提供现成的效果了,此时就需要监听滑动状态了,怎么做,看下面:

class _HomePageState extends State<HomePage> {
  List list = new List();
  ScrollController _scrollController;

  @override
  void initState() {
    super.initState();
    _refresh();
    _scrollController = ScrollController()
      ..addListener(() {
        //判断是否滑到底
        if (_scrollController.position.pixels ==
            _scrollController.position.maxScrollExtent) {
          _loadMore();
        }
      });
  }

  Future _loadMore() async {
    await Future.delayed(Duration(seconds: 2), () {
      setState(() {
        list.addAll(
            List.generate(Random().nextInt(5) + 1, (i) => 'more Item $i'));
      });
    });
  }

  Future<void> _refresh() async {
    await Future.delayed(Duration(seconds: 3), () {
      setState(() {
        list =
            List.generate(Random().nextInt(20) + 15, (i) => 'refresh Item $i');
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Flutter 下拉刷新、上拉加载示例'),
        ),
        body: Center(
          child: RefreshIndicator(
              displacement: 20,
              child: list == null || list.isEmpty
                  ? Center(
                      //如果为null则增加一个loading效果
                      child: CircularProgressIndicator(),
                    )
                  : ListView.builder(
                      controller: _scrollController,
                      itemCount: list.length + 1, //多加一个是为了实现分页效果
                      itemBuilder: (context, index) {
                        if (index == list.length) {
                          //如果是最后一行则增加个loading
                          return Padding(
                            padding: const EdgeInsets.all(10.0),
                            child: Center(
                              child: CircularProgressIndicator(),
                            ),
                          );
                        }
                        return ListTile(
                          title: Text(list[index]),
                        );
                      }),
              onRefresh: _refresh),
        ));
  }
}

效果就不演示了,如最初的样子。

ListView重排序:ReorderableListView

效果:

其实就是ListView的条目重排序功能,如下:

 

具体实现:

import 'dart:math';

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: HomePage(),
    ));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  List list = List.generate(Random().nextInt(15) + 1, (i) => 'Item $i');

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Flutter 列表重排序示例'),
        ),
        body: ReorderableListView(
          onReorder: _onReorder, //移动的回调
          children: list
              .map((m) => ListTile(
                    key: ObjectKey(m),
                    title: Text(m),
                  ))
              .toList(),
        ));
  }

  _onReorder(int oldIndex, int newIndex) {
    print('oldIndex: $oldIndex, newIndex: $newIndex');
  }
}

运行看一下打印日志:

接下来则需要处理一下回调的逻辑,达到真正的条目移动的效果,如下:

 

然后运行看一下效果:

貌似妥妥的,但是接下来如果将其拖到最后一个则会报错:

总共是四个元素,而移动到最后一个位置时的index为5了,所以此时需要做一个容错判断,如下:

运行:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Flutter MaterialApp API 是 Flutter 提供的一个核心组件,用于创建一个基于 Material Design 风格的应用程序。它是一个如何使用 Material Design 风格的应用程序的入口点。 MaterialApp API 提供了许多属性和方法,用于配置和自定义应用程序的外观和行为。其中一些要的属性包括: 1. title:应用程序的标题,它将显示在应用程序的任务栏或应用程序切换器上。 2. theme:应用程序的主题,包括颜色、字体和形状等。可以通过 ThemeData 类实例化一个主题对象,并将其分配给 theme 属性。 3. home:应用程序的主页,通常是一个 StatefulWidget 对象。当应用程序启动时,将显示主页的内容。 4. routes:定义应用程序的不同页面的路由,可以使用命名路由的方式进行导航。 5. initialRoute:定义应用程序初始显示的页面路由。当应用程序启动时,将自动跳转到指定的初始路由。 6. onGenerateRoute:定义一个函数,用于根据路由名称动态生成页面。可以通过该函数实现动态路由的功能。 7. navigatorObservers:定义一个列表,用于添加导航观察者。导航观察者可以用于监听页面的导航事件。 通过使用 MaterialApp API,我们可以轻松地创建一个基于 Material Design 风格的应用程序,并对其进行自定义和配置。它为我们提供了许多强大的功能和灵活的选项,使我们能够构建出符合用户期望并风格统一的 Flutter 应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

webor2006

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值