zoukankan      html  css  js  c++  java
  • Flutter项目实操---发现

    发现:

    列表显示:

    继续接着上一次https://www.cnblogs.com/webor2006/p/13098765.html的功能往下进行编写,接下来则来写发现这个页面的功能,先来看一下最终它长啥样?

    先来显示列表,关于列表的显示在我的界面中已经使用过了,这里再来快速的温故一下,目前发现只是占了一个位:

    import 'package:flutter/material.dart';
    
    class DiscoveryPage extends StatefulWidget {
      @override
      _DiscoveryPageState createState() => _DiscoveryPageState();
    }
    
    class _DiscoveryPageState extends State<DiscoveryPage> {
      @override
      Widget build(BuildContext context) {
        return Center(
          child: Text('发现'),
        );
      }
    }

    先定义个数组,代表列表选项:

    import 'package:flutter/material.dart';
    
    class DiscoveryPage extends StatefulWidget {
      @override
      _DiscoveryPageState createState() => _DiscoveryPageState();
    }
    
    class _DiscoveryPageState extends State<DiscoveryPage> {
      List<Map<String, IconData>> blocks = [
        {
          '开源众包': Icons.pageview,
          '开源软件': Icons.speaker_notes_off,
          '码云推荐': Icons.screen_share,
          '代码片段': Icons.assignment,
        },
        {
          '扫一扫': Icons.camera_alt,
          '摇一摇': Icons.camera,
        },
        {
          '码云封面人物': Icons.person,
          '线下活动': Icons.android,
        }
      ];
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child: Text('发现'),
        );
      }
    }

    为啥这次定义的数据分开了呢?

     

    这是因为本身这次的列表界面就有分组存在,看一下界面效果图就知道了:

    接下来继续, 先来显示一个轮廓:

    运行:

    接下来则每个块中得填充列表项,也就是ListView中再次嵌ListView,这种用法咱们还是第一次用,来瞅一下:

    import 'package:flutter/material.dart';
    
    class DiscoveryPage extends StatefulWidget {
      @override
      _DiscoveryPageState createState() => _DiscoveryPageState();
    }
    
    class _DiscoveryPageState extends State<DiscoveryPage> {
      List<Map<String, IconData>> blocks = [
        {
          '开源众包': Icons.pageview,
          '开源软件': Icons.speaker_notes_off,
          '码云推荐': Icons.screen_share,
          '代码片段': Icons.assignment,
        },
        {
          '扫一扫': Icons.camera_alt,
          '摇一摇': Icons.camera,
        },
        {
          '码云封面人物': Icons.person,
          '线下活动': Icons.android,
        }
      ];
    
      @override
      Widget build(BuildContext context) {
        return ListView.builder(
          itemCount: blocks.length,
          itemBuilder: (context, index) {
            return Container(
              height: 200.0,
              decoration: BoxDecoration(
                border: Border(
                  top: BorderSide(
                     1.0,
                    color: Color(0xffaaaaaa),
                  ),
                  bottom: BorderSide(
                     1.0,
                    color: Color(0xffaaaaaa),
                  ),
                ),
              ),
              child: ListView.separated(
                  itemBuilder: (context, itemIndex) {
                    return InkWell(
                      onTap: () {},
                      child: Container(
                        child: ListTile(
                          leading: Icon(blocks[index].values.elementAt(itemIndex)),
                          title: Text(blocks[index].keys.elementAt(itemIndex)),
                          trailing: Icon(Icons.arrow_forward_ios),
                        ),
                      ),
                    );
                  },
                  separatorBuilder: (context, itemIndex) {
                    return Divider();
                  },
                  itemCount: blocks[index].length),
            );
          },
        );
      }
    }

    运行看一下:

    不过布局看着有点别扭,原因是咱们这个高度定死了:

    发现内容出不来了:

    这是咋回事呢?由于咱们目前的场景是ListView里面又套了一个ListView,这里需要增加一个属性,如下:

    此时内容就正常了:

    接下来其实目前是有个问题的,目前由于用的手机分辨率比较高还看不出来,咱们换一台较低分辨率的演示一下就知道了:

    看到木有,滑不动了,其实是由于滑动事件对第一层的ListView给消费掉了,对于ListView里面再嵌ListView是会有滑动冲突的问题,这也是问题之所在,而在Flutter中解决滑动冲突非常之简单,加个属性就解决了,而在Android中想想是多么麻烦,具体如下:

    然后咱们再将块与块之间增加一点间距,好看一点,那如何增加呢?看修改:

    运行看一下效果:

    其中有个小细节提一下,在之前已经有提过:

    其实就是android material风格,看一下:

    就是这种效果。

    处理点击事件:

    开源众包:

    这里先来处理这块的点击:

    这里只以“开源众包”点击事件为例实现一下:

    然后找一个开源众包的URL,直接上开源中国的官网找一下链接:

    "https://zb.oschina.net/",是它,所以咱们写一下跳转,在之前的登录中已经用到了,直接贴代码:

    然后新建一个WebView的页面:

    import 'package:flutter/material.dart';
    
    class CommonWebPage extends StatefulWidget {
      final String title;
      final String url;
    
      CommonWebPage({Key key, this.title, this.url})
          : assert(title != null),
            assert(url != null),
            super(key: key);
    
      @override
      _CommonWebPageState createState() => _CommonWebPageState();
    }
    
    class _CommonWebPageState extends State<CommonWebPage> {
      @override
      Widget build(BuildContext context) {
        return Container();
      }
    }

    接下来则来编写这个WebView页面,之前已经使用过一次了,这里再来温故一下:

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_osc_client/constants/constants.dart';
    import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
    
    class CommonWebPage extends StatefulWidget {
      final String title;
      final String url;
    
      CommonWebPage({Key key, this.title, this.url})
          : assert(title != null),
            assert(url != null),
            super(key: key);
    
      @override
      _CommonWebPageState createState() => _CommonWebPageState();
    }
    
    class _CommonWebPageState extends State<CommonWebPage> {
      bool isLoading = true;
    
      @override
      Widget build(BuildContext context) {
        List<Widget> _appBarTitle = [
          Text(
            widget.title,
            style: TextStyle(
              color: Color(AppColors.APPBAR),
            ),
          ),
        ];
        if (isLoading) {
          _appBarTitle.add(SizedBox(
             10.0,
          ));
          _appBarTitle.add(CupertinoActivityIndicator());
        }
        return WebviewScaffold(
          url: widget.url,
          appBar: AppBar(
            title: Row(
              children: _appBarTitle,
            ),
            iconTheme: IconThemeData(color: Color(AppColors.APPBAR)), //0412 added
          ),
          withJavascript: true,
          //允许执行js
          withLocalStorage: true,
          //允许本地存储
          withZoom: true, //允许网页缩放
        );
      }
    }

    接下来增加WebView的监听:

    运行一下:

    扫一扫:

    接下来再来处理扫一扫的点击事件:

    对于扫一扫肯定得用三方开源的,所以用这个库来做:

    看一下怎么用的:

    然后看下拉取下来的版本号:

    所以:

    那如何调用呢?

    所以咱们来整一下:

    运行看一下:

    报错了。。上面错误提示说是需要改一下最小支持的sdk为16以上,其实改了之后还是报,这里换一个稍低的版本:

    然后再编译,发现还是出错:

    androidx,也就是咱们目前还是用的support,那具体怎么解决这个错呢,得按如下步骤改一下:

    1、修改 android/gradle/wrapper/gradle-wrapper.properties 为gradle-4.10.2-all.zip及以上:

    2、修改 android/build.gradle :

    groovy
    dependencies {
    classpath 'com.android.tools.build:gradle:3.2.1'
    }
    
    改为
    groovy
    dependencies {
    classpath 'com.android.tools.build:gradle:3.3.0'
    }

    改为:

    3、修改 android/gradle.properties,加上下面两句 :

    android.enableJetifier=true
    android.useAndroidX=true

    4、修改 android/app/build.gradle :
    首先,确保 compileSdkVersion 和 targetSdkVersion 至少为 28 :

    android{
        ...
        compileSdkVersion 28
        ...
        defaultConfig{
            ...
            targetSdkVersion 28
            ...
        }
        ...
    }

    5、将以下的support都改为androidx:

     

    一切修改就绪,接下来运行扫一扫,发现还是报错了:

     

    哦,难道是忘了加相机权限了,其实不是的,这是需要在项目工程下执行“flutter clean”既可以解决这个错,如下:

     

    然后再次运行就好了:

    咱们这里找一个二维码扫一下能出结果就成:

    摇一摇:

    添加点击事件:

    这个就稍复杂一些,先添加一个点击事件跳到一个页面:

    import 'package:flutter/material.dart';
    import 'package:flutter_osc_client/constants/constants.dart';
    
    class ShakePage extends StatefulWidget {
      @override
      _ShakePageState createState() => _ShakePageState();
    }
    
    class _ShakePageState extends State<ShakePage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            elevation: 0.0,
            title: Text(
              '摇一摇',
              style: TextStyle(color: Color(AppColors.APPBAR)),
            ),
            iconTheme: IconThemeData(color: Color(AppColors.APPBAR)),
          ),
          body: Center(
            child: Text('摇一摇'),
          ),
        );
      }
    }

    页面搭建:

    先来看一下它长啥样:

    所以咱们来搭建一下,由于这样的界面咱们在之前已经用过了,所以这里就不过多的解释说明了:

    import 'package:flutter/material.dart';
    import 'package:flutter_osc_client/constants/constants.dart';
    
    class ShakePage extends StatefulWidget {
      @override
      _ShakePageState createState() => _ShakePageState();
    }
    
    class _ShakePageState extends State<ShakePage> {
      bool isShaked = false;
      int _curentIndex = 0;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            elevation: 0.0,
            title: Text(
              '摇一摇',
              style: TextStyle(color: Color(AppColors.APPBAR)),
            ),
            iconTheme: IconThemeData(color: Color(AppColors.APPBAR)),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Image.asset(
                  'assets/images/shake.png',
                   120.0,
                  height: 120.0,
                ),
                SizedBox(
                  height: 10.0,
                ),
                Text('摇一摇获取礼品'),
              ],
            ),
          ),
          bottomNavigationBar: BottomNavigationBar(
            items: [
              BottomNavigationBarItem(icon: Icon(Icons.folder), title: Text('礼品')),
              BottomNavigationBarItem(
                  icon: Icon(Icons.assignment), title: Text('资讯'))
            ],
            currentIndex: _curentIndex,
            onTap: (index) {
              if (!mounted) return;
              setState(() {
                _curentIndex = index;
              });
            },
          ),
        );
      }
    }

    其中用到了一个新图片:

    在yaml文件中声明一下:

    运行:

    开始实现:

    1、集成三方依赖库:

    这里对于摇一摇其实没有太成熟好用的库,不过也能搜到一些,比如:

    但是这里采用自己来编写逻辑,只集成传感器的功能库,如下:

    而它的使用看一下:

    所以咱们来将它集成进来:

    2、增加加速度感应监听:

    3、摇一摇逻辑实现:

    接下来则实现摇一摇的具体处理,不过先来给它加一个震动,此时又需要用到三方的库了:

    import 'dart:async';
    import 'dart:math';
    
    import 'package:flutter/material.dart';
    import 'package:flutter_osc_client/constants/constants.dart';
    import 'package:sensors/sensors.dart';
    import 'package:vibration/vibration.dart';
    
    class ShakePage extends StatefulWidget {
      @override
      _ShakePageState createState() => _ShakePageState();
    }
    
    class _ShakePageState extends State<ShakePage> {
      bool isShaked = false;
      int _curentIndex = 0;
      StreamSubscription _streamSubscription;
      static const int SHAKE_TIMEOUT = 500;
      static const double SHAKE_THRESHOLD = 3.25;
      var _lastTime = 0;
    
      @override
      void initState() {
        super.initState();
        _streamSubscription =
            accelerometerEvents.listen((AccelerometerEvent event) {
          var now = DateTime.now().millisecondsSinceEpoch;
          if ((now - _lastTime) > SHAKE_TIMEOUT) {
            //获得加速度的x,y,z值
            var x = event.x;
            var y = event.y;
            var z = event.z;
            double acce =
                sqrt(x * x + y * y + z * z) - 9.8; //9.8是g,加速度公式,貌似是初中的物理,反正我是忘了
            if (acce > SHAKE_THRESHOLD) {
              print('摇一摇');
              //手机晃动了
              Vibration.vibrate();
              _lastTime = now;
              if (!mounted) return;
              setState(() {
                isShaked = true;
              });
            }
          }
        });
      }
    
      @override
      void dispose() {
        super.dispose();
        _streamSubscription.cancel();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            elevation: 0.0,
            title: Text(
              '摇一摇',
              style: TextStyle(color: Color(AppColors.APPBAR)),
            ),
            iconTheme: IconThemeData(color: Color(AppColors.APPBAR)),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Image.asset(
                  'assets/images/shake.png',
                   120.0,
                  height: 120.0,
                ),
                SizedBox(
                  height: 10.0,
                ),
                Text(isShaked ? '活动已结束!' : '摇一摇获取礼品'),
              ],
            ),
          ),
          bottomNavigationBar: BottomNavigationBar(
            items: [
              BottomNavigationBarItem(icon: Icon(Icons.folder), title: Text('礼品')),
              BottomNavigationBarItem(
                  icon: Icon(Icons.assignment), title: Text('资讯'))
            ],
            currentIndex: _curentIndex,
            onTap: (index) {
              if (!mounted) return;
              setState(() {
                _curentIndex = index;
                isShaked = false;
              });
            },
          ),
        );
      }
    }

    下面咱们运行试一下:

    图片中感知不到震动与摇动,具体自行体验下既可,当然摇一摇应该得去请求相应的接口的,这里由于木有相关接口就暂且忽略了。

  • 相关阅读:
    php-有时候你会疑惑的小问题
    phpDocumentor生成文档
    mongodb重命名集合、数据库
    资料网站
    Service(服务)
    Component(组件)
    Module(模块)
    你不屑于大器晚成,就只能平庸一生
    是狼就磨好牙,是羊就练好腿!
    将Excel数据导入数据库
  • 原文地址:https://www.cnblogs.com/webor2006/p/13186045.html
Copyright © 2011-2022 走看看