功能引导 android,Flutter实现App功能引导页

App功能介绍页,主要是由介绍app功能的几张图片和当前页指示符组成,如下效果

1e2d56f454f2d007c9b226a5da4c251a.png

我们来一步一步实现上面的界面,左右滑动切换显示功能页,这个可以通过PageView来实现,底部的指示符半透明覆盖在PageView上,开发过Android同学知道可以用Framelayout布局来实现,Flutter上也有类似的控件Stack,我们先完成骨架代码

// An highlighted block

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

class App extends StatelessWidget {

@override

Widget build(BuildContext context) {

return MaterialApp(

title: 'Title',

theme: ThemeData(

primarySwatch: Colors.blue,

),

home: AppFuncBrowse(),

);

}

}

class AppFuncBrowse extends StatefulWidget {

@override

_AppFuncBrowseState createState() {

return _AppFuncBrowseState();

}

}

class _AppFuncBrowseState extends State {

@override

Widget build(BuildContext context) {

return Scaffold(

body: Container(

color: Colors.white,

child: Stack(

children: [

],

),

));

}

}

AppFuncBrowse 就是我们功能介绍页,上面编译运行功能后,我们先来着手实现功能介绍页面切换,PageView主要有两类构建函数,一个是懒加载页面(适合页面很多时使用),一个是适合少量页面的一次性加载的,我们实例显示3个页面,就简单的用这种方式, PageView用到了PageController用来控制显示哪一页,先定义它

class _AppFuncBrowseState extends State {

PageController _pageController = PageController();

//省略...

}

有了PageController我们就可以创建PageView,代码如下

Widget _createPageView() {

return PageView(

controller: _pageController,

onPageChanged: (pageIndex) {

setState(() {

_pageIndex = pageIndex;

print(_pageController.page);

print(pageIndex);

});

},

children: [

Container(

color: Colors.blue,

child: Center(

child: Text('Page 1'),

),

),

Container(

color: Colors.red,

child: Center(

child: Text('Page 2'),

),

),

Container(

color: Colors.green,

child: Center(

child: Text('Page 3'),

),

),

],

);

}

@override

Widget build(BuildContext context) {

// TODO: implement build

return Scaffold(

body: Container(

color: Colors.white,

// margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top),

child: Stack(

children: [

_createPageView(),

],

),

));

}

bf5ae0669cd3de0ad0e73a982c213d42.png

到这里我们完成了一个可以左右滑动的功能页, 每页的内容大家可以自定义,一般是一张图片,我这里为了简单起见直接显示Text,到目前为止我们离目标还缺一个页码指示器,学过iOS的非常熟悉,需要用到UIPageControl,可惜的是到目前为止Flutter还没提供该原生控件,我们只能自己实现它,其实也很简单,代码如下:

_createPageIndicator() {

return Opacity(

opacity: 0.7,

child: Align(

alignment: FractionalOffset.bottomCenter,

child: Container(

margin: EdgeInsets.only(bottom: 60),

height: 40,

width: 80,

padding: EdgeInsets.all(0),

decoration: BoxDecoration(

color: Colors.grey, //.withAlpha(128),

borderRadius: BorderRadius.all(const Radius.circular(6.0))),

child: GestureDetector(

behavior: HitTestBehavior.translucent,

onTapUp: (detail) => _handlePageIndicatorTap(detail),

child: Row(

key: _pageIndicatorKey,

mainAxisAlignment: MainAxisAlignment.spaceEvenly,

mainAxisSize: MainAxisSize.min,

children: [

_dotWidget(0),

_dotWidget(1),

_dotWidget(2),

]),

),

),

),

);

}

咋一看感觉好复杂,其实也很简单,学过设计模式的同学可能看出和装饰者模式一样,widget层次结构就类似这种模式,这也是Flutter的强大之处,用现有的控件可以组合出各种效果,首先我们用Opacity控件来封装子控件,设置opacity使其成为半透明,然后使用Align控制其底部对齐,为了使其距离底部一段距离,还需要Container来包装,为了实现圆角的Container,强大的decoration属性就登场了,它能实现各种装饰效果,这里我们实现的效果是灰色背景和圆角。

现在讲完了这些装修,就剩下三个点了,三个点在同一水平线上,所以我们用Row来做为父控件,Row有几个属性值注意

mainAxisAlignment      主轴对齐方式,Row的主轴是水平方向,

crossAxisAlignment     主轴的垂直方向对齐方式,Row的主轴是水平方向,所以该字段表示上下对齐方式

mainAxisSize           主轴方向的大小,对Row来说即宽度

与Row对应的控件是Column,其对应上面属性刚好相反

上面属性的其他值可以自己试验,我们这里用到

mainAxisAlignment: MainAxisAlignment.spaceEvenly,

mainAxisSize: MainAxisSize.min,

表示子控件左右(包含与父控件)间距相同,并且宽度保持最小,最后我们来实现三个点,当前页的对应的点颜色需要和其他未显示的页有所区别,我们需要记录当前是第几页,从而使对应的第几个点highlight显示

class _AppFuncBrowseState extends State {

PageController _pageController = PageController();

int _pageIndex = 0;

然后就可以创建点了

_dotWidget(int index) {

return Container(

width: 10,

height: 10,

decoration: BoxDecoration(

shape: BoxShape.circle,

color: (_pageIndex == index) ? Colors.white70 : Colors.black12));

}

滑动PageView,需要更新_pageIndex,从而对应的更新当前页对应的点的颜色

return PageView(

controller: _pageController,

onPageChanged: (pageIndex) {

setState(() {

_pageIndex = pageIndex;

print(_pageController.page);

print(pageIndex);

});

},

onPageChanged就是PageView换页的事件,这里需要调用setState从而使Widget重建更新当前页的点颜色

到这里为止就剩下点击点更新PageView的功能了,我们来实现点击功能,就是监听点击手势,代码如下

_handlePageIndicatorTap(TapUpDetails detail) {

RenderBox renderBox =

_pageIndicatorKey.currentContext.findRenderObject();

Size widgeSize = renderBox.paintBounds.size;

Offset tapOffset =

renderBox.globalToLocal(detail.globalPosition);

if (tapOffset.dx > widgeSize.width / 2) {

_scrollToNextPage();

} else {

_scrollToPreviousPage();

}

}

手势有一个属性behavior需要值得注意,默认值为deferToChild,具体取值如下:

behavior: HitTestBehavior.translucent 控制响应的点击区域:

translucent    表示整个区域,被遮挡的子视图也能响应

opaque          表示整个区域,被遮挡的子视图不能响应

deferToChild    表示点击到子视图才响应,手势默认behavior

需要实现点击左半部分向前翻页,点击后半部分向后翻页,我们需要判断当前点击的区域,这就需要找到Row的RenderObject来获取控件区域,然后获取点击相对控件的偏移来确定,具体见代码,_pageIndicatorKey就是传给Row的key,具体定义如下

class _AppFuncBrowseState extends State {

PageController _pageController = PageController();

int _pageIndex = 0;

GlobalKey<_appfuncbrowsestate> _pageIndicatorKey = GlobalKey();

现在只剩下前后翻页的代码了,代码如下

_scrollToPreviousPage() {

if (_pageIndex > 0) {

_pageController.animateToPage(_pageIndex - 1,

duration: const Duration(milliseconds: 200), curve: Curves.ease);

}

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值