郭大鹏

郭大鹏 查看完整档案

唐山编辑唐山师范学院  |  软件开发与项目管理 编辑唐山市轻回车网络科技有限公司  |  PHP工程师 编辑 my.oschina.net/guodapeng 编辑
编辑

不讲理才可爱!

个人动态

郭大鹏 关注了标签 · 10月9日

spring

Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。

关注 25537

郭大鹏 报名了系列讲座 · 9月2日

从计算到智能-AI带来哪些机遇与挑战

**华为云第四季技术开放日活动开始啦!本次活动由华为公司与思否编程联合举办,邀请了业界知名的大咖讲师带来精彩的线上系列直播分享!** **👉👉👉本场直播由北京航空航天大学副教授-秦曾昌老师为您带来了《从计算到智能》,具体安排如下:** ##### 直播时间 2020年9月3日 本周四 晚 8:00-9:00 ##### 讲师介绍 秦曾昌老师 * 北京航空航天大学副教授 * 英国布里斯托大学硕士、博士 * 美国加州大学伯克利分校博士后 * 牛津大学与卡内基梅隆大学访问学者 * 教育部新世纪优秀人才获得者 ##### 内容概览 1. 介绍计算发展的历史与人工智能的本质 2. 如何从计算的角度来模仿人类的智能 3. AI算法给社会与生活带来的机遇与挑战 ![直播页面.jpg](https://live-static.segmentfault.com/380/466/3804668651-5f4ce00390a0a) 拥抱AI,欢迎大家积极参与! [1]: /img/bVbMlbE

郭大鹏 收藏了文章 · 5月16日

Flutter 10天高仿大厂App及小技巧积累总结

2880040dd20bac8885929d5859b5e525.jpg

之前,也写过几篇关于 Flutter 的博文,最近,又花了一些时间学习研究 Flutter,完成了高仿大厂 App 项目 (项目使用的接口都是来自线上真实App抓包而来,可以做到和线上项目相同的效果),也总结积累了一些小技巧和知识点,所以,在这里记录分享出来,也希望 Flutter 生态越来越好 (flutter开发App效率真的很高,开发体验也是很好的 🙂)

以下博文会分为3个部分概述:

  • 项目结构分析
  • 项目功能详细概述(所用知识点)
  • 小技巧积累总结

项目结构分析

其次,梳理下项目的目录结构,理解每个文件都是干什么的,我们先来看看一级目录,如下:

├── README.md  # 描述文件
├── android    # android 宿主环境
├── build      # 项目构建目录,由flutter自动完成
├── flutter_ctrip.iml
├── fonts      # 自己创建的目录,用于存放字体
├── images     # 自己创建的目录,用于存放图片
├── ios        # iOS 宿主环境
├── lib        # flutter 执行文件,自己写的代码都在这
├── pubspec.lock # 用来记录锁定插件版本
├── pubspec.yaml # 插件及资源配置文件
└── test       # 测试目录

这个就不用多解释,大多是 flutter 生成及管理的,我们需要关注的是 lib 目录。

我们再来看看二级目录,如下 (重点关注下lib目录)

├── README.md
├── android
│   ├── android.iml
  ...
│   └── settings.gradle
├── build
│   ├── app
  ...
│   └── snapshot_blob.bin.d.fingerprint
├── flutter_ctrip.iml
├── fonts
│   ├── PingFang-Italic.ttf
│   ├── PingFang-Regular.ttf
│   └── PingFang_Bold.ttf
├── images
│   ├── grid-nav-items-dingzhi.png
  ...
│   └── yuyin.png
├── ios
│   ├── Flutter
  ...
│   └── ServiceDefinitions.json
├── lib
│   ├── dao           # 请求接口的类
│   ├── main.dart     # flutter 入口文件
│   ├── model         # 实体类,把服务器返回的 json 数据,转换成 dart 类
│   ├── navigator     # bottom bar 首页底部导航路由
│   ├── pages         # 所以的页面
│   ├── plugin        # 封装的插件
│   ├── util          # 工具类,避免重复代码,封装成工具类以便各个 page 调用
│   └── widget        # 封装的组件
├── pubspec.lock
├── pubspec.yaml
└── test
    └── widget_test.dart

再来看看,lib 目录下二级目录,看看整个项目创建了多少个文件,写了多少代码,如下 (其实,并不是很多)

├── dao/
│   ├── destination_dao.dart*
│   ├── destination_search_dao.dart*
│   ├── home_dao.dart
│   ├── search_dao.dart*
│   ├── trave_hot_keyword_dao.dart*
│   ├── trave_search_dao.dart*
│   ├── trave_search_hot_dao.dart*
│   ├── travel_dao.dart*
│   ├── travel_params_dao.dart*
│   └── travel_tab_dao.dart*
├── main.dart
├── model/
│   ├── common_model.dart
│   ├── config_model.dart
│   ├── destination_model.dart
│   ├── destination_search_model.dart
│   ├── grid_nav_model.dart
│   ├── home_model.dart
│   ├── sales_box_model.dart
│   ├── seach_model.dart*
│   ├── travel_hot_keyword_model.dart
│   ├── travel_model.dart*
│   ├── travel_params_model.dart*
│   ├── travel_search_hot_model.dart
│   ├── travel_search_model.dart
│   └── travel_tab_model.dart
├── navigator/
│   └── tab_navigater.dart
├── pages/
│   ├── destination_page.dart
│   ├── destination_search_page.dart
│   ├── home_page.dart
│   ├── my_page.dart
│   ├── search_page.dart
│   ├── speak_page.dart*
│   ├── test_page.dart
│   ├── travel_page.dart
│   ├── travel_search_page.dart
│   └── travel_tab_page.dart*
├── plugin/
│   ├── asr_manager.dart*
│   ├── side_page_view.dart
│   ├── square_swiper_pagination.dart
│   └── vertical_tab_view.dart
├── util/
│   └── navigator_util.dart*
└── widget/
    ├── grid_nav.dart
    ├── grid_nav_new.dart
    ├── loading_container.dart
    ├── local_nav.dart
    ├── sales_box.dart
    ├── scalable_box.dart
    ├── search_bar.dart*
    ├── sub_nav.dart
    └── webview.dart

整个项目就是以上这些文件了 (具体的就不一个一个分析了,如,感兴趣,大家可以 clone 源码运行起来,自然就清除了)

项目功能详细概述(所用知识点)

首先,来看看首页功能及所用知识点,首页重点看下以下功能实现:

  • 渐隐渐现的 appBbar
  • 搜索组件的封装
  • 语音搜索页面
  • banner组件
  • 浮动的 icon 导航
  • 渐变不规则带有背景图的网格导航

渐隐渐现的 appBbar

先来看看具体效果,一睹芳容,如图:

appBar

滚动的时候 appBar 背景色从透明变成白色或白色变成透明,这里主要用了 flutterNotificationListener 组件,它会去监听组件树冒泡事件,当被它包裹的的组件(子组件) 发生变化时,Notification 回调函数会被触发,所以,通过它可以去监听页面的滚动,来动态改变 appBar 的透明度(alpha),代码如下:

NotificationListener(
  onNotification: (scrollNotification) {
    if (scrollNotification is ScrollUpdateNotification &&
        scrollNotification.depth == 0) {
      _onScroll(scrollNotification.metrics.pixels);
    }
    return true;
  },
  child: ...

Tips:
scrollNotification.depth 的值 0 表示其子组件(只监听子组件,不监听孙组件)
scrollNotification is ScrollUpdateNotification 来判断组件是否已更新,ScrollUpdateNotification 是 notifications 的生命周期一种情况,分别有一下几种:

  • ScrollStartNotification 组件开始滚动
  • ScrollUpdateNotification 组件位置已经发生改变
  • ScrollEndNotification 组件停止滚动
  • UserScrollNotification 不清楚

这里,我们不探究太深入,如想了解可多查看源码。

_onScroll 方法代码如下:

  void _onScroll(offset) {
    double alpha = offset / APPBAR_SCROLL_OFFSET;  // APPBAR_SCROLL_OFFSET 常量,值:100;offset 滚动的距离

    //把 alpha 值控制值 0-1 之间
    if (alpha < 0) {
      alpha = 0;
    } else if (alpha > 1) {
      alpha = 1;
    }
    setState(() {
      appBarAlpha = alpha;
    });
    print(alpha);
  }

搜索组件的封装

搜索组件效果如图:

searchBar

以下是首页调用 searchBar 的代码:

SearchBar(
  searchBarType: appBarAlpha > 0.2  //searchBar 的类:暗色、亮色
      ? SearchBarType.homeLight
      : SearchBarType.home,
  inputBoxClick: _jumpToSearch,     //点击回调函数
  defaultText: SEARCH_BAR_DEFAULT_TEXT,   // 提示文字
  leftButtonClick: () {},           //左边边按钮点击回调函数
  speakClick: _jumpToSpeak,         //点击话筒回调函数
  rightButtonClick: _jumpToUser,    //右边边按钮点击回调函数
),

其实就是用 TextField 组件,再加一些样式,需要注意点是:onChanged,他是 TextField 用来监听文本框是否变化,通过它我们来监听用户输入,来请求接口数据;
具体的实现细节,请查阅源码: 点击查看searchBar源码

语音搜索页面

语音搜索页面效果如图:由于模拟器无法录音,所以无法展示正常流程,如果录音识别成功后会返回搜索页面,在项目预览视频中可以看到正常流程。

no-shadow

语音搜索功能使用的是百度的语言识别SDK,原生接入之后,通过 MethodChannel 和原生Native端通信,这里不做重点讲述(这里会涉及原生Native的知识)。

重点看看点击录音按钮时的动画实现,这个动画用了 AnimatedWidget 实现的,代码如下:

class AnimatedWear extends AnimatedWidget {
  final bool isStart;
  static final _opacityTween = Tween<double>(begin: 0.5, end: 0); // 设置透明度变化值
  static final _sizeTween = Tween<double>(begin: 90, end: 260);   // 设置圆形线的扩散值

  AnimatedWear({Key key, this.isStart, Animation<double> animation})
      : super(key: key, listenable: animation);

  @override
  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;  // listenable 继承 AnimatedWidget,其实就是控制器,会自动监听组件的变化
    return Container(
      height: 90,
      width: 90,
      child: Stack(
        overflow: Overflow.visible,
        alignment: Alignment.center,
        children: <Widget>[
          ...
          // 扩散的圆线,其实就是用一个圆实现的,设置圆为透明,设置border
          Positioned(
            left: -((_sizeTween.evaluate(animation) - 90) / 2), // 根据 _sizeTween 动态设置left偏移值
            top: -((_sizeTween.evaluate(animation) - 90) / 2), //  根据 _sizeTween 动态设置top偏移值
            child: Opacity(
              opacity: _opacityTween.evaluate(animation),      // 根据 _opacityTween 动态设置透明值
              child: Container(
                width: isStart ? _sizeTween.evaluate(animation) : 0, // 设置 宽
                height: _sizeTween.evaluate(animation),              // 设置 高
                decoration: BoxDecoration(
                    color: Colors.transparent,
                    borderRadius: BorderRadius.circular(
                        _sizeTween.evaluate(animation) / 2),
                    border: Border.all(
                      color: Color(0xa8000000),
                    )),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

其他细节,如:点击时提示录音,录音失败提示,点击录音按钮出现半透明黑色圆边框,停止后消失等,请查看源码

banner组件

效果如图:

no-shadow

banner使用的是flutter的 flutter_swiper 插件实现的,代码如下:

Swiper(
  itemCount: bannerList.length,              // 滚动图片的数量
  autoplay: true,                            // 自动播放
  pagination: SwiperPagination(              // 指示器
      builder: SquareSwiperPagination(
        size: 6,                             // 指示器的大小
        activeSize: 6,                       // 激活状态指示器的大小
        color: Colors.white.withAlpha(80),   // 颜色
        activeColor: Colors.white,           // 激活状态的颜色
      ),
    alignment: Alignment.bottomRight,        // 对齐方式
    margin: EdgeInsets.fromLTRB(0, 0, 14, 28), // 边距
  ),
  itemBuilder: (BuildContext context, int index) { // 构造器
    return GestureDetector(
      onTap: () {
        CommonModel model = bannerList[index];
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => WebView(
              url: model.url,
            ),
          ),
        );
      },
      child: Image.network(
        bannerList[index].icon,
        fit: BoxFit.fill,
      ),
    );
  },
),

具体使用方法,可以去 flutter的官方插件库 pub.dev 查看:点击flutter_swiper查看

Tips:
需要注意的是,我稍改造了一下指示器的样式,flutter_swiper 只提供了 3 种指示器样式,如下:

  • dots = const DotSwiperPaginationBuilder(),圆形
  • fraction = const FractionPaginationBuilder(),百分数类型的,如:1/6,表示6页的第一页
  • rect = const RectSwiperPaginationBuilder(),矩形

并没有上图的激活状态的长椭圆形,其实就是按葫芦画瓢,自己实现一个长椭圆类型,如知详情,可点击查看长椭圆形指示器源码

浮动的 icon 导航

icon导航效果如图:

iconBar

icon导航浮动在banner之上,其实用的是 flutterStack 组件,Stack 组件能让其子组件堆叠显示,它通常和 Positioned 组件配合使用,布局结构代码如下:

ListView(
  children: <Widget>[
    Container(
      child: Stack(
        children: <Widget>[
          Container( ... ), //这里放的是banner的代码
          Positioned( ... ), //这个就是icon导航,通过 Positioned 固定显示位置
        ],
      ),
    ),
    Container( ... ), // 这里放的网格导航及其他
  ],
),

渐变不规则带有背景图的网格导航

网格导航效果如图:

gridNav

如图,网格导航分为三行四栏,而第一行分为三栏,每一行的第一栏宽度大于其余三栏,其余三栏均等,每一行都有渐变色,而且第一、二栏都有背景图;
flutterColumn 组件能让子组件竖轴排列, Row 组件能让子组件横轴排列,布局代码如下:

Column(                      // 最外面放在 Column 组件
  children: <Widget>[
    Container(               // 第一行包裹 Container 设置其渐变色
      height: 72,
      decoration: BoxDecoration(
        gradient: LinearGradient(colors: [  //设置渐变色
          Color(0xfffa5956),
          Color(0xffef9c76).withAlpha(45)
        ]),
      ),
      child: Row( ... ),    // 第一行
    ),
    Padding(
      padding: EdgeInsets.only(top: 1),  // 设置行直接的间隔
    ),
    Container(
      height: 72,
      decoration: BoxDecoration(
        gradient: LinearGradient(colors: [  //设置渐变色
          Color(0xff4b8fed),
          Color(0xff53bced),
        ]),
      ),
      child: Row( ... ),  // 第二行
    ),
    Padding(
      padding: EdgeInsets.only(top: 1),   // 设置行直接的间隔
    ),
    Container(
      height: 72,
      decoration: BoxDecoration(
        gradient: LinearGradient(colors: [  //设置渐变色
          Color(0xff34c2aa),
          Color(0xff6cd557),
        ]),
      ),
      child: Row( ... ),  // 第三行
    ),
  ],
),

其实,具体实现的细节还是很多的,比如:

  • 怎么设置第一栏宽度偏大,其他均等;
  • 第一行最后一栏宽度是其他的2倍;
  • 第一、二栏的别截图及浮动的红色气泡tip等;

在这里就不细讲,否则篇幅太长,如想了解详情 点击查看源码

其次,再来看看目的地页面功能及所用知识点,重点看下以下功能实现:

  • 左右布局tabBarListView
  • 目的地搜索页面

左右布局tabBarListView

具体效果如图:点击左边标签可以切换页面,左右滑动也可切换页面,点击展开显示更多等

no-shadow

其实官方已经提供了 tabBarTabBarView 组件可以实现上下布局的效果(旅拍页面就是用这个实现的),但是它无法实现左右布局,而且不太灵活,所以,我使用的是 vertical_tabs插件, 代码如下:

VerticalTabView(
    tabsWidth: 88,
    tabsElevation: 0,
    indicatorWidth: 0,
    selectedTabBackgroundColor: Colors.white,
    backgroundColor: Colors.white,
    tabTextStyle: TextStyle(
      height: 60,
      color: Color(0xff333333),
    ),
    tabs: tabs,
    contents: tabPages,
  ),
),

具体使用方法,在这里就不赘述了,点击vertical_tabs查看

Tips:
这里需要注意的是:展开显示更多span标签组件的实现,因为,这个组件在很多的其他组件里用到而且要根据接口数据动态渲染,且组件自身存在状态的变化,这种情况下,最好是把他单独封装成一个组件(widget),否则,很难控制自身状态的变化,出现点击没有效果,或点击影响其他组件。

目的地搜索页面

效果如图:点击搜索结果,如:点击‘一日游‘,会搜索到‘一日游‘的相关数据

no-shadow

目的地搜索页面,大多都是和布局和对接接口的代码,在这里就不再赘述。

然后就是旅拍页面功能及所用知识点,重点看下以下功能实现:

  • 左右布局tabBarListView
  • 瀑布流卡片
  • 旅拍搜索页

左右布局tabBarListView

效果如图:可左右滑动切换页面,上拉加载更多,下拉刷新等

no-shadow

这个是flutter 提供的组件,tabBarTabBarView,代码如下:

Container(
  color: Colors.white,
  padding: EdgeInsets.only(left: 2),
  child: TabBar(
    controller: _controller,
    isScrollable: true,
    labelColor: Colors.black,
    labelPadding: EdgeInsets.fromLTRB(8, 6, 8, 0),
    indicatorColor: Color(0xff2FCFBB),
    indicatorPadding: EdgeInsets.all(6),
    indicatorSize: TabBarIndicatorSize.label,
    indicatorWeight: 2.2,
    labelStyle: TextStyle(fontSize: 18),
    unselectedLabelStyle: TextStyle(fontSize: 15),
    tabs: tabs.map<Tab>((Groups tab) {
      return Tab(
        text: tab.name,
      );
    }).toList(),
  ),
),
Flexible(
    child: Container(
  padding: EdgeInsets.fromLTRB(6, 3, 6, 0),
  child: TabBarView(
      controller: _controller,
      children: tabs.map((Groups tab) {
        return TravelTabPage(
          travelUrl: travelParamsModel?.url,
          params: travelParamsModel?.params,
          groupChannelCode: tab?.code,
        );
      }).toList()),
)),

瀑布流卡片

瀑布流卡片 用的是 flutter_staggered_grid_view 插件,代码如下:

StaggeredGridView.countBuilder(
  controller: _scrollController,
  crossAxisCount: 4,
  itemCount: travelItems?.length ?? 0,
  itemBuilder: (BuildContext context, int index) => _TravelItem(
        index: index,
        item: travelItems[index],
      ),
  staggeredTileBuilder: (int index) => new StaggeredTile.fit(2),
  mainAxisSpacing: 2.0,
  crossAxisSpacing: 2.0,
),

如下了解更多相关信息,点击flutter_staggered_grid_view查看

旅拍搜索页

效果如图:首先显示热门旅拍标签,点击可搜索相关内容,输入关键字可搜索相关旅拍信息,地点、景点、用户等

no-shadow

旅拍搜索页,大多也是和布局和对接接口的代码,在这里就不再赘述。

小技巧积累总结

以下都是我在项目里使用的知识点,在这里记录分享出来,希望能帮到大家。

PhysicalModel

PhysicalModel 可以裁剪带背景图的容器,如,你在一个 Container 里放了一张图片,想设置图片圆角,设置 Container 的 decoration 的 borderRadius 是无效的,这时候就要用到 PhysicalModel,代码如下:

PhysicalModel(
  borderRadius: BorderRadius.circular(6),  // 设置圆角
  clipBehavior: Clip.antiAlias,            // 裁剪行为
  color: Colors.transparent,               // 颜色
  elevation: 5,                            // 设置阴影
  child: Container(
        child: Image.network(
          picUrl,
          fit: BoxFit.cover,
        ),
      ),
),

LinearGradient

给容器添加渐变色,在网格导航、appBar等地方都使用到,代码如下:

Container(
  height: 72,
  decoration: BoxDecoration(
    gradient: LinearGradient(colors: [
      Color(0xff4b8fed),
      Color(0xff53bced),
    ]),
  ),
  child: ...
),

Color(int.parse('0xff' + gridNavItem.startColor))

颜色值转换成颜色,如果,没有变量的话,也可直接这样用 Color(0xff53bced)

  • ox:flutter要求,可固定不变
  • ff:代表透明贴,不知道如何设置的话,可以用取色器,或者 withOpacity(opacity) 、 withAlpha(a)
  • 53bced: 常规的6位RGB值

Expanded、FractionallySizedBox

Expanded 可以让子组件撑满父容器,通常和 RowColumn 组件搭配使用;


FractionallySizedBox 可以让子组件撑满或超出父容器,可以单独使用,大小受 widthFactor 和 heightFactor 宽高因子的影响

MediaQuery.removePadding

MediaQuery.removePadding 可以移除组件的边距,有些组件自带有边距,有时候布局的时候,不需要边距,这时候就可以用 MediaQuery.removePadding,代码如下:

MediaQuery.removePadding(
  removeTop: true,
  context: context,
  child: ...
)

MediaQuery.of(context).size.width

MediaQuery.of(context).size.width 获取屏幕的宽度,同理,MediaQuery.of(context).size.height 获取屏幕的高度;
如,想一行平均3等分: 0.3 * MediaQuery.of(context).size.width,在目的地页面的标签组件就使用到它,代码如下:

Container(
  alignment: Alignment.center,
  ...
  width: 0.3*MediaQuery.of(context).size.width - 12, // 屏幕平分三等分, - 12 是给每份中间留出空间 
  height: 40,
  ...
  child: ...
),

Theme.of(context).platform == TargetPlatform.iOS

判断操作系统类型,有时候可能有给 Andorid 和 iOS 做出不同的布局,就需要用到它。

with AutomaticKeepAliveClientMixin

flutter 在切换页面时候每次都会重新加载数据,如果想让页面保留状态,不重新加载,就需要使用 AutomaticKeepAliveClientMixin,代码如下:(在旅拍页面就有使用到它,为了让tabBar 和 tabBarView在切换时不重新加载)

class TravelTabPage extends StatefulWidget {
  ...
  //需要重写 wantKeepAlive 且 设置成 true
  @override
  bool get wantKeepAlive => true;
}

暂时只能想到这些常用的知识点,以后如有新的会慢慢补充。

博客地址:https://lishaoy.net
博客Notes地址:https://h.lishaoy.net
项目GitHub地址:https://github.com/persilee/flutter_ctrip

查看原文

郭大鹏 收藏了文章 · 5月16日

基于 Flutter+Dart 聊天实例 | Flutter 仿微信界面聊天室

1、项目介绍

Flutter是目前比较流行的跨平台开发技术,凭借其出色的性能获得很多前端技术爱好者的关注,比如阿里闲鱼美团腾讯等大公司都有投入相关案例生产使用。
flutter_chatroom项目是基于Flutter+Dart+chewie+photo_view+image_picker等技术开发的跨平台仿微信app聊天界面应用,实现了消息/表情发送、图片预览、长按菜单、红包/小视频/朋友圈等功能。
022360截图20200512003659242.png

2、技术框架

  • 使用技术:Flutter 1.12.13/Dart 2.7.0
  • 视频组件:chewie: ^0.9.7
  • 图片/拍照:image_picker: ^0.6.6+1
  • 图片预览组件:photo_view: ^0.9.2
  • 弹窗组件:showModalBottomSheet/AlertDialog/SnackBar
  • 本地存储:shared_preferences: ^0.5.7+1
  • 字体图标:阿里iconfont字体图标库

001360截图20200512002407906.png

003360截图20200512002631530.png

004360截图20200512002755155.png

005360截图20200512002840849.png

007360截图20200512002934978.png

008360截图20200512003004490.png

009360截图20200512003023266.png

011360截图20200512003108139.png

014360截图20200512003208370.png

016360截图20200512003322336.png

018360截图20200512003422368.png

019360截图20200512003435098.png

021360截图20200512003604679.png

023360截图20200512003901929.png

026360截图20200512004446202.png

025360截图20200512004305675.png

029360截图20200512004708377.png

031360截图20200512005508992.png

鉴于flutter基于dart语言,需要安装Dart Sdk / Flutter Sdk,至于如何搭建开发环境,可以去官网查阅文档资料

https://flutter.cn/

https://flutterchina.club/

https://pub.flutter-io.cn/

https://www.dartcn.com/

使用vscode编辑器,可先安装DartFlutterFlutter widget snippets等扩展插件

3、flutter沉浸式状态栏/底部tabbar

flutter中如何实现顶部全背景沉浸式透明状态栏(去掉状态栏黑色半透明背景),去掉右上角banner,可以去看这篇文章
https://segmentfault.com/a/11...

4、flutter图标组件/IconData自定义封装组件

  • 1、使用系统图标组件: Icon(Icons.search) 
  • 2、使用IconData方式: Icon(IconData(0xe60e, fontFamily:'iconfont'), size:24.0)

使用第二种方式需要先下载阿里图标库字体文件,然后在pubspec.yaml中引入字体
360截图20200513090806912.png

class GStyle {
    // __ 自定义图标
    static iconfont(int codePoint, {double size = 16.0, Color color}) {
        return Icon(
            IconData(codePoint, fontFamily: 'iconfont', matchTextDirection: true),
            size: size,
            color: color,
        );
    }
}

调用非常简单,可自定义颜色、字体大小;
GStyle.iconfont(0xe635, color: Colors.orange, size: 17.0)

5、flutter实现badge红点/圆点提示

360截图20200513091117720.png
如上图:在flutter中没有圆点提示组件,需要自己封装实现;

class GStyle {
    // 消息红点
    static badge(int count, {Color color = Colors.red, bool isdot = false, double height = 18.0, double width = 18.0}) {
        final _num = count > 99 ? '···' : count;
        return Container(
            alignment: Alignment.center, height: !isdot ? height : height/2, width: !isdot ? width : width/2,
            decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(100.0)),
            child: !isdot ? Text('$_num', style: TextStyle(color: Colors.white, fontSize: 12.0)) : null
        );
    }
}

支持自定义红点大小、颜色,默认数字超过99就...显示;
GStyle.badge(0, isdot:true)
GStyle.badge(13)
GStyle.badge(29, color: Colors.orange, height: 15.0, width: 15.0)

6、flutter长按自定义弹窗

  • 在flutter中如何实现长按,并在长按位置弹出菜单,类似微信消息长按弹窗效果;

360截图20200513091947231.png
通过InkWell组件提供的onTapDown事件获取坐标点实现

InkWell(
    splashColor: Colors.grey[200],
    child: Container(...),
    onTapDown: (TapDownDetails details) {
        _globalPositionX = details.globalPosition.dx;
        _globalPositionY = details.globalPosition.dy;
    },
    onLongPress: () {
        _showPopupMenu(context);
    },
),
// 长按弹窗
double _globalPositionX = 0.0; //长按位置的横坐标
double _globalPositionY = 0.0; //长按位置的纵坐标
void _showPopupMenu(BuildContext context) {
    // 确定点击位置在左侧还是右侧
    bool isLeft = _globalPositionX > MediaQuery.of(context).size.width/2 ? false : true;
    // 确定点击位置在上半屏幕还是下半屏幕
    bool isTop = _globalPositionY > MediaQuery.of(context).size.height/2 ? false : true;

    showDialog(
      context: context,
      builder: (context) {
        return Stack(
          children: <Widget>[
            Positioned(
              top: isTop ? _globalPositionY : _globalPositionY - 200.0,
              left: isLeft ? _globalPositionX : _globalPositionX - 120.0,
              width: 120.0,
              child: Material(
                ...
              ),
            )
          ],
        );
      }
    );
}
  • flutter如何实现去掉AlertDialog弹窗大小限制?

可通过SizedBox和无限制容器UnconstrainedBox组件实现

void _showCardPopup(BuildContext context) {
    showDialog(
      context: context,
      builder: (context) {
        return UnconstrainedBox(
          constrainedAxis: Axis.vertical,
          child: SizedBox(
            width: 260,
            child: AlertDialog(
              content: Container(
                ...
              ),
              elevation: 0,
              contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
            ),
          ),
        );
      }
    );
}

7、flutter登录/注册表单|本地存储

flutter提供了两个文本框组件:TextFieldTextFormField
本文是使用TextField实现,并在文本框后添加清空文本框/密码查看图标

TextField(
  keyboardType: TextInputType.phone,
  controller: TextEditingController.fromValue(TextEditingValue(
    text: formObj['tel'],
    selection: new TextSelection.fromPosition(TextPosition(affinity: TextAffinity.downstream, offset: formObj['tel'].length))
  )),
  decoration: InputDecoration(
    hintText: "请输入手机号",
    isDense: true,
    hintStyle: TextStyle(fontSize: 14.0),
    suffixIcon: Visibility(
      visible: formObj['tel'].isNotEmpty,
      child: InkWell(
        child: GStyle.iconfont(0xe69f, color: Colors.grey, size: 14.0), onTap: () {
          setState(() { formObj['tel'] = ''; });
        }
      ),
    ),
    border: OutlineInputBorder(borderSide: BorderSide.none)
  ),
  onChanged: (val) {
    setState(() { formObj['tel'] = val; });
  },
)

TextField(
  decoration: InputDecoration(
    hintText: "请输入密码",
    isDense: true,
    hintStyle: TextStyle(fontSize: 14.0),
    suffixIcon: InkWell(
      child: Icon(formObj['isObscureText'] ? Icons.visibility_off : Icons.visibility, color: Colors.grey, size: 14.0),
      onTap: () {
        setState(() {
          formObj['isObscureText'] = !formObj['isObscureText'];
        });
      },
    ),
    border: OutlineInputBorder(borderSide: BorderSide.none)
  ),
  obscureText: formObj['isObscureText'],
  onChanged: (val) {
    setState(() { formObj['pwd'] = val; });
  },
)

验证消息提示则是使用flutter提供的SnackBar实现

// SnackBar提示
final _scaffoldkey = new GlobalKey<ScaffoldState>();
void _snackbar(String title, {Color color}) {
    _scaffoldkey.currentState.showSnackBar(SnackBar(
      backgroundColor: color ?? Colors.redAccent,
      content: Text(title),
      duration: Duration(seconds: 1),
    ));
}

另外本地存储使用的是shared\_preferences,至于如何使用可参看
https://pub.flutter-io.cn/packages/shared_preferences

void handleSubmit() async {
    if(formObj['tel'] == '') {
      _snackbar('手机号不能为空');
    }else if(!Util.checkTel(formObj['tel'])) {
      _snackbar('手机号格式有误');
    }else if(formObj['pwd'] == '') {
      _snackbar('密码不能为空');
    }else {
      // ...接口数据

      // 设置存储信息
      final prefs = await SharedPreferences.getInstance();
      prefs.setBool('hasLogin', true);
      prefs.setInt('user', int.parse(formObj['tel']));
      prefs.setString('token', Util.setToken());

      _snackbar('恭喜你,登录成功', color: Colors.greenAccent[400]);
      Timer(Duration(seconds: 2), (){
        Navigator.pushNamedAndRemoveUntil(context, '/tabbarpage', (route) => route == null);
      });
    }
}

8、flutter聊天页面功能

360截图20200513093616798.png

  • 在flutter中如何实现类似上图编辑器功能?通过TextField提供的多行文本框属性maxLines就可实现。
Container(
    margin: GStyle.margin(10.0),
    decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(3.0)),
    constraints: BoxConstraints(minHeight: 30.0, maxHeight: 150.0),
    child: TextField(
        maxLines: null,
        keyboardType: TextInputType.multiline,
        decoration: InputDecoration(
          hintStyle: TextStyle(fontSize: 14.0),
          isDense: true,
          contentPadding: EdgeInsets.all(5.0),
          border: OutlineInputBorder(borderSide: BorderSide.none)
        ),
        controller: _textEditingController,
        focusNode: _focusNode,
        onChanged: (val) {
          setState(() {
            editorLastCursor = _textEditingController.selection.baseOffset;
          });
        },
        onTap: () {handleEditorTaped();},
    ),
),
  • flutter实现滚动聊天信息到最底部

通过ListView里controller属性提供的jumpTo方法及_msgController.position.maxScrollExtent

ScrollController _msgController = new ScrollController();
...
ListView(
    controller: _msgController,
    padding: EdgeInsets.all(10.0),
    children: renderMsgTpl(),
)

// 滚动消息至聊天底部
void scrollMsgBottom() {
    timer = Timer(Duration(milliseconds: 100), () => _msgController.jumpTo(_msgController.position.maxScrollExtent));
}

行了,基于flutter/dart开发聊天室实例就介绍到这里,希望能喜欢~~💪💪

最后附上electron桌面端应用实例
electron聊天室|vue+electron-vue仿微信客户端|electron桌面聊天
360截图20190807103937042.jpg

查看原文

郭大鹏 回答了问题 · 4月28日

七牛云推流到阿里云上,推流地址报授权错误

客服说,新的SDK给第三方推流,授权要好几万呢,以前的不收影响……

关注 3 回答 2

郭大鹏 收藏了文章 · 4月14日

简单说 CSS中的 object-fit 与 object-position

说明

问题:
一个div宽度不固定,高度固定,采用Flex布局,它里面有两个元素一个img宽度占40%,高度占100%,一个p元素,宽度占60%,高度占100%,调整浏览器窗口大小,要保证,img元素不变形,宽高比不变,怎么办!

图片描述

从图中可以看出,随着调整浏览器窗口,图片的宽高比也被破坏了,我们该怎么办呢?我想大家应该会想到用 background,用一个div的background来替代img元素,这样就可以调整它的background-size 和 background-position,就能保证图片不变形,宽高比不变了,但是其实不用这么麻烦,我们直接用 object-fit 与 object-position 就可以了。

效果图:

图片描述

代码:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8"> 
    <style type="text/css">
    div{
        height: 300px;
        border: 1px solid red;
        display: flex;
    }

    img {
        width: 40%;
        height: 100%;

        /*只是增加下面两行就可以了*/
        object-fit: none;
        object-position: center;  /*这行都可以不写,object-position 默认就是 center*/
    }

    p{
        width: 60%;
        height: 100%;
        background: blue;
        margin: 0;
        overflow: hidden;
    }
    </style>
</head>

<body>
    <div>
        <img data-original="http://img.blog.csdn.net/20171016170931485">
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
    </div>
</body>

</html>

上面是object-fit取值为 none 的情况,我们看看object-fit取值为 contain 的情况。
这里写图片描述

好的,问题解决了,我们来具体看看 object-fit 与 object-position 这两个属性

解释

object-fit 属性

这个属性决定了像img和videos这样的替换元素的内容应该如何使用他的宽度和高度来填充其容器。

object-fit 具体有5个值:

图片描述

替换元素:

其内容不受CSS视觉格式化模型控制的元素,比如img,嵌入的文档(iframe之类)或者applet,叫做替换元素。比:img元素的内容通常会被其src属性指定的图像替换掉。替换元素通常有其固有的尺寸:一个固有的宽度,一个固有的高度和一个固有的比率。比如一幅位图有固有用绝对单位指定的宽度和高度,从而也有固有的宽高比率。另一方面,其他文档也可能没有固有的尺寸,比如一个空白的html文档。

CSS渲染模型不考虑替换元素内容的渲染。这些替换元素的展现独立于CSS。object,video,textarea,input也是替换元素,audio和canvas在某些特定情形下为替换元素。使用CSS的content属性插入的对象是匿名替换元素。

我们来看看,每个属性值,起作用的样子

图片描述

图片描述

因为scal-down 就是 none和contain之间进行选择,选择的是尺寸比较小的那个 ,所以它是始终能保证替换元素完整显示的,并且它显示的最大尺寸就是图片实际尺寸。

object-position 属性

object-position 用来控制替换内容位置

图片描述

语法:
object-position:x轴距离 y轴距离;

object-position属性定义时可以用像素,也可以用百分比,也可以用关键字。例如,object-position: 10px 10px 是左上角各空出10px,object-position: 100% 100%是右下角,object-position: center 是中间 和 object-position: 50% 50% 效果一样。

我们来看看各种取值的效果

图片描述

图片描述

图片描述

图片描述

图片描述

注意:
1、object-position属性与background-position很相似,其取值和background-position属性取值一样,但是它的默认值是50% 50%, background-position的默认值是0% 0%
2、如果仅指定了一个值,其他值将是50%

总结

这两个属性,主要是解决在布局时遇到的 尺寸 和 宽高比问题,说简单点就是处理图片会变形的问题,而object-position默认值是 50% 50% ,就是居中的意思,也可以用这两个属性来做 替换元素 的内容的水平垂直居中。

查看原文

郭大鹏 回答了问题 · 4月13日

有没有办法自定义 border 为 dashed 时的虚线间距?

@哔哔肾 “鸭式辨型” 这个有意思,思路开阔。

来个伪类写的分割线

      &:after
        width 10px
        height calc(100% - .1rem)
        background-image linear-gradient(to bottom, #ccc 0%, #ccc 50%, transparent 50%)
        background-size 1px 8px
        background-repeat repeat-y
        position absolute
        top 0.25em
        left -0.42rem
        content ''

父级给两个属性

      position relative
      margin .42rem

这个实现出来的,在iOS与android上基本是一致的效果,质量较高的还原了设计师的设计。

关注 6 回答 6

郭大鹏 赞了回答 · 4月13日

有没有办法自定义 border 为 dashed 时的虚线间距?

可以的,用渐变

width: 100%;
height: 1px;
background-image: linear-gradient(to right, #ccc 0%, #ccc 50%, transparent 50%);
background-size: 8px 1px;
background-repeat: repeat-x;

关注 6 回答 6

郭大鹏 报名了系列讲座 · 3月22日

【思否编程公开课】游戏制作人招募(兼职),Reworld教你简单开发好玩的游戏

##### 内容介绍: 如果你会编程,热爱游戏,有创作游戏的想法,现在只需要一台电脑和创意即可轻松做出好玩的游戏。 Reworld 物理引擎是一款极具创造性的 3D 游戏创作工具,游戏类型不受限制;具有天然物理属性,将现实中的力和约束拟真到游戏中;其内置商店有免费美术、特效、音频、模型等海量素材,在创作中按需拖拽即可;这些功能旨在能够很大程度降低游戏开发难度,提升效率,使游戏创作更简单有趣。使用 Reworld 物理引擎创作的游戏,上传到游戏平台后可以在 PC、安卓、iOS 平台完美运行。 本次直播中除了 Reworld 物理引擎功能介绍,还将现场展示开发出一款好玩的游戏,观看直播的开发者也可以参与进来,感受创作游戏的乐趣。 **直播主要内容:** * 游戏及游戏行业的概述 * 游戏开发的乐趣:简单的游戏机制 * Reworld游戏制作人招募 ##### 交流沟通: ![图片描述][1] [1]: /img/bVbEeV7

郭大鹏 报名了系列讲座 · 3月22日

【思否编程公开课】走进互联网应用—从单体应用到微服务

####直播回顾转码中 ###内容介绍 绍目前互联网应用开发的主流框架,包括:Spring、SpringMVC、MyBatis、SpringBoot以及SpringCloud,讲解技术更新迭代的过程,以及大型项目的架构设计思想。 ###入群交流: ![图片描述][1] [1]: /img/bVbEnku

郭大鹏 报名了系列讲座 · 3月6日

如何快速开发一款小程序

【课程说明】 微信小程序自 2017 年上线以来,小程序的数量和小程序的开发者持续增长,它以一种极度轻量化、无处不在、用完即走的方式全面连接人与服务,在给用户带来更好的体验的同时,大幅降低开发门槛和成本。 本期 Open Talk ,又拍云邀请无码科技、有赞、大搜车、二维火等知名企业的微信小程序开发者,为广大开发者带来一场了解小程序开发生态、学习小程序开发经验、探索小程序的更多应用可能的技术分享。 Open Talk 是由又拍云发起的系列主题分享沙龙,秉承又拍云帮助企业提升发展速度的初衷,从 2015 年开启以来,Open Talk 至今已成功举办 50 余期,辐射线上线下近十万技术人群,分别在北京、上海、广州、深圳、杭州、武汉等 12 座城市举办,覆盖腾讯、华为、网易、京东、唯品会、斗鱼、哔哩哔哩、美团点评等诸多知名企业。不管是从某个“主题”出发横向拓展技术干货分享,还是以某个“品牌企业”为主纵深丰富演讲内容,活动都场场爆满。 【课程福利】 又拍云推出开发者帮助计划,为开发者提供专业、免费、稳定的 CDN 及云存储服务,加速个人网站及 APP 等项目。即日起加入又拍云联盟,每月独享 10GB 免费存储空间和 15GB 免费 CDN 流量,更多详情请前往又拍云官网查询。

郭大鹏 报名了系列讲座 · 3月6日

【思否编程公开课】 PostgreSQL 12 新特性

主讲人: digoal PostgreSQL中文社区发起人之一,生态常委 内容介绍: PostgreSQL 12新版本开发者特性介绍,数据库行业未来风向标

郭大鹏 报名了系列讲座 · 3月6日

快速上手 MySQL读写分离/分库分表中间件

## DBLE 介绍 破壳日:2017.10.24 爱好:开源 技能:数据水平拆分、兼容MySQL、高可用性、SQL支持、复杂查询优化、分布式事务支持 特长:兼容性、复杂查询、分布式事务的深入改进优化 作为一个高性能、高可靠性,低成本,可弹性扩展的开源分布式数据库中间件,DBLE 具有读写分离,分库分表,故障自动切换,原生 MySQL 协议支持,跨平台等特性,可灵活构建不同规模的数据库集群,通过将业务数据分片到不同的数据库存储节点中,充分利用各节点的计算资源, 极大地提高了数据库的性能。 ## 课程目标 用短视频的课程形式,帮助用户快速上手 DBLE 的安装、目录结构、基本功能和一些进阶分析功能。最终掌握 DBLE 的基础操作。 全新的 DBLE 课程,带给你全新的 D[ou]ble 的学习体验!!! ## 适宜人群 对 DBLE 感兴趣的用户; 正在使用 MyCat 等其它分布式中间件的用户; 当前中间件无法满足业务需求的用户; 运维大体量数据库,需要考虑分库分表的DBA; 为数据库架构选型发愁的研发人员; ## 课程大纲 全套课程共 18 课,总时长约 2 小时; 具体分为: 1.安装介绍 -DBLE项目介绍 -Docker安装方式介绍 -普通安装方式 -目录结构演示 2.基本功能 -水平拆分 -复杂查询 -不同拆分规则的表 -Golbal表简介 -ER表实现方法1 -ER表实现方法2 -Hint 简介和演示 3.进阶功能 -全局序列介绍 -全局序列演示 -管理端介绍 -权限&黑白名单 4.分析功能 -进阶功能 Explain -进阶功能 Trace -慢查询日志

郭大鹏 报名了系列讲座 · 2月29日

【思否编程公开课】迎接Vue 3.0

内容介绍: Vue 3.0的新变化 开发团队的设计思路(为什么会有这些变化) 我们应该怎么准备 讲师介绍: 讲师:大家好,我叫翟路佳,花名“肉山”,这个名字跟 Dota 没关系,从高中起伴随我到现在。我热爱生活,热爱编程;喜欢学习,喜欢分享;从业十多年,投入比较多,学习积累也比较多,对前端方方面面都有所了解,希望能与大家分享。 我目前是一名全栈工程师,就职于 OpenResty Inc.,关注前端里各种垂直深耕的领域,也喜欢研究工具链、设计模式、自动化测试等工程问题。

郭大鹏 报名了系列讲座 · 2月29日

kubernetes 入门

## 课程大纲 1. 安装 centos7 2. 什么是 kubernetes 3. 部署 kubernetes 集群 4. kubernetes 核心概念介绍以及基本命令实操 ## 适宜人群 有 docker 基础 ## 课程说明 本课程是免费的,听到就是赚到,会给大家介绍 k8s,带领大家入门 k8s。现在的容器技术这么火爆,很有必要了解掌握下 k8s。欢迎大家加入我的 QQ 群:963643807

郭大鹏 报名了系列讲座 · 2月29日

开源分布式关系型数据库 TiDB

## 课程大纲 [TiDB](https://pingcap.com) 是一款定位于在线事务处理/在线分析处理(HTAP: Hybrid Transactional/Analytical Processing)的融合型数据库产品,实现了一键水平伸缩,强一致性的多副本数据安全,分布式事务,实时 OLAP 等重要特性。同时兼容 MySQL 协议和生态,迁移便捷,运维成本极低。 [TiDB](https://github.com/pingcap/tidb) 目前在 GitHub Star 数超过 20k,其分布式存储层项目 [TiKV](https://github.com/tikv/tikv) 已晋升为 CNCF(云原生计算基金会)的孵化项目。 **本课程将通过一系列不同时期的 Infra Meetup 现场分享视频,带大家了解 TiDB 架构与技术细节。** >注意: > >+ 本视频为 **2019 年不同时期 Infra Meetup 相关视频集锦**,所相关技术细节均基于 Meetup 当天的 TiDB 版本,请大家观看时注意区分。附:[TiDB 版本发布时间](https://pingcap.com/docs-cn/v3.0/releases/rn/)。 > >+ 本课程内容免费公开,也欢迎大家之后能够参与 [线下的 Infra Meetup 活动](https://pingcap.com/community-cn/)。Infra Meetup 是 PingCAP 定期举办的系列线下交流活动,主题覆盖基础架构领域的前瞻性技术思考与经验。自 2016 年开始已成功举办 100 余期,落地北京、上海、广州、成都、杭州、深圳、西安等城市。PingCAP 希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 | 序号 | Infra Meetup 时间 / 期数 | Topic| Speaker | |:-------|:-----------------|:-------------------|:-----------| | 1 | 2019-04-20 第 97 期 | 《What's New in TiDB 3.0 》 | 申砾,PingCAP 技术 VP | | 2 | 2019-05-11 第 101 期| 《The Evolution of TiKV》 | 唐刘,PingCAP 首席架构师 | | 3 | 2019-06-02 第 106 期| 《TiDB 的 HTAP 之路 - 过去,现在和将来》 | 马晓宇,PingCAP 分析型产品负责人 | | 4 | 2019-03-16 第 91 期|《Head First Transaction in TiDB》 | 吴雪莲,PingCAP 研发工程师 | | 5 | 2019-06-15 第 108 期| 《Deep Dive into TiDB DDL》| 李霞,PingCAP 研发工程师| | 6 | 2019-03-30 第 95 期|《Introduction to TiDB SQL Layer》| 姚珂男,PingCAP 研发工程师| | 7 | 2019-04-13 第 96 期 | 《Introduction to Titan》| 张博康,PingCAP 研发工程师 | | 8 | 2019-09-07 第 113 期 |《TiDB Operator 的设计与实现》| 尹亮,PingCAP 研发工程师| | 9 | 2019-05-18 第 102 期 | 《TiDB Ecosystem Tools 概览》 | 杨非,PingCAP 研发工程师| | 10 | 2019-09-07 第 114 期 | 《TiDB 高可用架构的设计要点》| 李坤,PingCAP 互联网架构师| ## 适宜人群 + 数据库领域从业者 / 爱好者,关注前沿技术 + 开源爱好者,Geek + 对分布式关系型数据库 [TiDB 的整体架构](https://pingcap.com/docs-cn/v3.0/overview/) 有所了解 ## 课程说明 + 再次强调:由于本系列视频由不同时期的 Meetup 现场视频集结而成,所以请大家注意区分视频中的产品版本。 + 更多资料: - 官方微信:PingCAP (菜单栏有很多资料可以发掘) - [官方博客](https://pingcap.com/blog-cn/) - [官方文档](https://pingcap.com/docs-cn/stable/) - [社区活动](https://pingcap.com/community-cn/)

郭大鹏 报名了系列讲座 · 2月29日

OpenResty 最佳实践

【课程说明】 OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项,用于便捷搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。 为促进 OpenResty 在技术圈的发展,增进 OpenResty 使用者的交流与学习,OpenResty 社区联合又拍云,举办 “OpenResty × Open Talk” 全国巡回沙龙,邀请业内资深的 OpenResty 技术专家,分享 OpenResty 实战经验,推动 OpenResty 开源项目的发展,促进互联网技术的教育。 又拍云 Open Talk 是由又拍云发起的系列主题分享沙龙,秉承又拍云帮助企业提升发展速度的初衷,从 2015 年开启以来,Open Talk 至今已成功举办 50 余期,辐射线上线下近十万技术人群,分别在北京、上海、广州、深圳、杭州、武汉等 12 座城市举办,覆盖腾讯、华为、网易、京东、唯品会、斗鱼、哔哩哔哩、美团点评、有赞等诸多知名企业。 【适宜人群】 本课程适合工作3-5年的,正在使用 OpenResty 或者对其有兴趣的开发爱好者。 【课程福利】 又拍云推出开发者帮助计划,为开发者提供专业、免费、稳定的 CDN 及云存储服务,加速个人网站及 APP 等项目。即日起加入又拍云联盟,每月独享 10GB 免费存储空间和 15GB 免费 CDN 流量,更多详情请前往又拍云官网查询。

郭大鹏 报名了系列讲座 · 2月29日

融云微课堂第五讲 | 基于原生代码开发 Flutter 插件

Flutter 是谷歌发布的移动 UI 框架 一经推出便受到了广泛关注 如何快速掌握 Flutter 插件开发技术 快速地在iOS和Android上构建高质量的原生用户界面 成为了很多开发者面对的难题 融云微课堂第五讲 手把手教你如何基于原生代码开发 Flutter 插件

郭大鹏 报名了系列讲座 · 2月29日

Flutter 社区技术视频

Flutter 技术视频合集,发布最新 Flutter 中文字幕或者中文语言 / 配音课程。

郭大鹏 回答了问题 · 2月6日

解决Stack 设置 Overflow.visible 后 虽然显示 UI 了 但是点击不到

又是自问自答的……
截屏2020-02-06下午2.22.04.png

解决时的 GIT 代码

大体思路是 Stack 把到我要盖的东西包起来。

provider 库做状态管理。

不过我感觉官网文档确实不好理解,我是花了8个小时才搞搞定的。

var filterBarData = Provider.of<FilterBarModel>(context);

这个很重要,用来获得 ChangeNotifier 对象,我一开始老是 new 这个东西,对官方文档有误解,我一直以为这个会是个单例一样的东西,但是我感觉实际上不是的。

参考链接:

简单的应用状态管理

关注 1 回答 1