亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用Flutter實(shí)現(xiàn)一個(gè)走馬燈布局的示例代碼

 更新時(shí)間:2019年11月25日 10:45:08   作者:ColdStone  
這篇文章主要介紹了使用 Flutter 實(shí)現(xiàn)一個(gè)走馬燈布局的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

走馬燈是一種常見的效果,本文講一下如何用 PageViewFlutter 里實(shí)現(xiàn)一個(gè)走馬燈, 效果如下,當(dāng)前頁面的高度比其它頁面高,切換頁面的時(shí)候有一個(gè)高度變化的動(dòng)畫。實(shí)現(xiàn)這樣的效果主要用到的是 PageView.builder 部件。

 

開發(fā)

 創(chuàng)建首頁

首先創(chuàng)建一個(gè) IndexPage 部件,這個(gè)部件用來放 PageView ,因?yàn)樾枰褂?setState 方法更新 UI,所以它是 stateful 的。

import 'package:flutter/material.dart';

class IndexPage extends StatefulWidget {
 @override
 _IndexPageState createState() => _IndexPageState();
}

class _IndexPageState extends State<IndexPage> {
 @override
 Widget build(BuildContext context) {
 return Scaffold(
 appBar: AppBar(
 elevation: 0.0,
 backgroundColor: Colors.white,
 ),
 body: Column(
 children: <Widget>[],
 ),
 );
 }
}

然后在部件內(nèi)申明一個(gè) _pageIndex 變量用來保存當(dāng)前顯示的頁面的 index,在 initState 生命周期里面初始化一個(gè) PageController 用來配置 PageView 部件。

bodyColumn 里面創(chuàng)建一個(gè) PageView.builder ,使用一個(gè) SizedBox 部件指定 PageView 的高度,將 controller 設(shè)置為 _pageController ,在 onPageChanged 事件里將當(dāng)前顯示頁面的 index 值賦值給 _pageIndex 變量。

int _pageIndex = 0;
PageController _pageController;

@override
void initState() {
 super.initState();
 _pageController = PageController(
 initialPage: 0,
 viewportFraction: 0.8,
 );
}

body: Column(
 children: <Widget>[
 SizedBox(
 height: 580.0,
 child: PageView.builder(
 itemCount: 3,
 pageSnapping: true,
 controller: _pageController,
 onPageChanged: (int index) {
  setState(() {
  _pageIndex = index;
  });
 },
 itemBuilder: (BuildContext ctx, int index) {
  return _buildItem(_pageIndex, index);
 },
 ),
 ),
 ],
),

關(guān)鍵點(diǎn): 設(shè)置 PageControllerviewportFraction 參數(shù)小于 1,這個(gè)值是用來設(shè)置每個(gè)頁面在屏幕上顯示的比例,小于 1 的話,就可以在當(dāng)前頁面同時(shí)顯示其它頁面的內(nèi)容了。

/// The fraction of the viewport that each page should occupy.
/// Defaults to 1.0, which means each page fills the viewport in the scrolling direction.
final double viewportFraction;

實(shí)現(xiàn) _buildItem

接著實(shí)現(xiàn) _buildItem 方法,這個(gè)方法就是返回 PageView.builder 里每一個(gè)頁面渲染的內(nèi)容,第一個(gè)參數(shù) activeIndex 是當(dāng)前顯示在屏幕上頁面的 index ,第二個(gè)參數(shù) index 是每一項(xiàng)自己的 index

使用一個(gè) Center 部件讓內(nèi)容居中顯示,然后用一個(gè) AnimatedContainer 添加頁面切換時(shí)的高度變化的動(dòng)畫效果,切換頁面的時(shí)候使用了 setState 方法改變了 _pageIndex , Flutter 重新繪制每一項(xiàng)。關(guān)鍵點(diǎn)在于判斷當(dāng)前頁面是否為正在顯示的頁面,是的話它的高度就是 500 不是的話就是 450。

_buildItem(activeIndex, index) {
 return Center(
 child: AnimatedContainer(
 curve: Curves.easeInOut,
 duration: Duration(milliseconds: 300),
 height: activeIndex == index ? 500.0 : 450.0,
 margin: EdgeInsets.symmetric(vertical: 20.0, horizontal: 10.0),
 decoration: BoxDecoration(
 color: heroes[index].color,
 borderRadius: BorderRadius.all(Radius.circular(12.0)),
 ),
 child: Stack(),
 ),
 );
}

 

添加內(nèi)容

然后給 AnimatedContainer 添加每一項(xiàng)的內(nèi)容

child: Stack(
 fit: StackFit.expand,
 children: <Widget>[
 ClipRRect(
 borderRadius: BorderRadius.all(
 Radius.circular(12.0),
 ),
 child: Image.network(
 heroes[index].image,
 fit: BoxFit.cover,
 ),
 ),
 Align(
 alignment: Alignment.bottomCenter,
 child: Row(
 children: <Widget>[
  Expanded(
  child: Container(
  padding: EdgeInsets.all(12.0),
  decoration: BoxDecoration(
  color: Colors.black26,
  borderRadius: BorderRadius.only(
   bottomRight: Radius.circular(12.0),
   bottomLeft: Radius.circular(12.0),
  ),
  ),
  child: Text(
  heroes[index].title,
  textAlign: TextAlign.center,
  style: TextStyle(
   fontSize: 20.0,
   fontWeight: FontWeight.bold,
   color: Colors.white,
  ),
  ),
  ),
  )
 ],
 ),
 ),
 ],
),

實(shí)現(xiàn)指示器

然后實(shí)現(xiàn)頁面的指示器,創(chuàng)建一個(gè) PageIndicator 部件,需要傳入 pageCount 表示總頁數(shù),以及 currentIndex 表示當(dāng)前顯示的頁數(shù)索引。把所有指示器放在一個(gè) Row 部件里,判斷當(dāng)前指示器的 index 是否為正在顯示頁面的 index ,是的話顯示較深的顏色。

class PageIndicator extends StatelessWidget {
 final int pageCount;
 final int currentIndex;

 const PageIndicator(this.currentIndex, this.pageCount);

 Widget _indicator(bool isActive) {
 return Container(
 width: 6.0,
 height: 6.0,
 margin: EdgeInsets.symmetric(horizontal: 3.0),
 decoration: BoxDecoration(
 color: isActive ? Color(0xff666a84) : Color(0xffb9bcca),
 shape: BoxShape.circle,
 boxShadow: [
  BoxShadow(
  color: Colors.black12,
  offset: Offset(0.0, 3.0),
  blurRadius: 3.0,
  ),
 ],
 ),
 );
 }

 List<Widget> _buildIndicators() {
 List<Widget> indicators = [];
 for (int i = 0; i < pageCount; i++) {
 indicators.add(i == currentIndex ? _indicator(true) : _indicator(false));
 }
 return indicators;
 }

 @override
 Widget build(BuildContext context) {
 return Row(
 mainAxisAlignment: MainAxisAlignment.center,
 children: _buildIndicators(),
 );
 }
}

添加 PageIndicatorSizedBox 下面

封裝 Carousel

最后的最后優(yōu)化一下代碼,把部件封裝一下,讓它成為一個(gè)單獨(dú)的部件,創(chuàng)建一個(gè) Carousel 部件,對(duì)外暴露 itemsheight 兩個(gè)屬性,分別配置數(shù)據(jù)和高度。

class Carousel extends StatefulWidget {
 final List items;
 final double height;

 const Carousel({
 @required this.items,
 @required this.height,
 });

 @override
 _CarouselState createState() => _CarouselState();
}

class _CarouselState extends State<Carousel> {
 int _pageIndex = 0;
 PageController _pageController;

 Widget _buildItem(activeIndex, index) {
 final items = widget.items;

 return Center(
 child: AnimatedContainer(
 curve: Curves.easeInOut,
 duration: Duration(milliseconds: 300),
 height: activeIndex == index ? 500.0 : 450.0,
 margin: EdgeInsets.symmetric(vertical: 20.0, horizontal: 10.0),
 decoration: BoxDecoration(
  color: items[index].color,
  borderRadius: BorderRadius.all(Radius.circular(12.0)),
 ),
 child: Stack(
  fit: StackFit.expand,
  children: <Widget>[
  ClipRRect(
  borderRadius: BorderRadius.all(
  Radius.circular(12.0),
  ),
  child: Image.network(
  items[index].image,
  fit: BoxFit.cover,
  ),
  ),
  Align(
  alignment: Alignment.bottomCenter,
  child: Row(
  children: <Widget>[
   Expanded(
   child: Container(
   padding: EdgeInsets.all(12.0),
   decoration: BoxDecoration(
   color: Colors.black26,
   borderRadius: BorderRadius.only(
    bottomRight: Radius.circular(12.0),
    bottomLeft: Radius.circular(12.0),
   ),
   ),
   child: Text(
   items[index].title,
   textAlign: TextAlign.center,
   style: TextStyle(
    fontSize: 20.0,
    fontWeight: FontWeight.bold,
    color: Colors.white,
   ),
   ),
   ),
   )
  ],
  ),
  ),
  ],
 ),
 ),
 );
 }

 @override
 void initState() {
 super.initState();
 _pageController = PageController(
 initialPage: 0,
 viewportFraction: 0.8,
 );
 }

 @override
 Widget build(BuildContext context) {
 return Column(
 children: <Widget>[
 Container(
  height: widget.height,
  child: PageView.builder(
  pageSnapping: true,
  itemCount: heroes.length,
  controller: _pageController,
  onPageChanged: (int index) {
  setState(() {
  _pageIndex = index;
  });
  },
  itemBuilder: (BuildContext ctx, int index) {
  return _buildItem(_pageIndex, index);
  },
  ),
 ),
 PageIndicator(_pageIndex, widget.items.length),
 ],
 );
 }
}

之后在 IndexPage 部件里就只用實(shí)例化一個(gè) Carousel 了,同時(shí)由于 IndexPage 不用管理部件狀態(tài)了,可以將它變成 StatelessWidget 。

完整代碼

import 'package:flutter/material.dart';

class Hero {
 final Color color;
 final String image;
 final String title;

 Hero({
 @required this.color,
 @required this.image,
 @required this.title,
 });
}

List heroes = [
 Hero(
 color: Color(0xFF86F3FB),
 image: "https://game.gtimg.cn/images/lol/act/img/skin/big22009.jpg",
 title: '寒冰射手-艾希',
 ),
 Hero(
 color: Color(0xFF7D6588),
 image: "https://game.gtimg.cn/images/lol/act/img/skin/big39006.jpg",
 title: '刀鋒舞者-艾瑞莉婭',
 ),
 Hero(
 color: Color(0xFF4C314D),
 image: "https://game.gtimg.cn/images/lol/act/img/skin/big103015.jpg",
 title: '九尾妖狐-阿貍',
 ),
];

class Carousel extends StatefulWidget {
 final List items;
 final double height;

 const Carousel({
 @required this.items,
 @required this.height,
 });

 @override
 _CarouselState createState() => _CarouselState();
}

class _CarouselState extends State<Carousel> {
 int _pageIndex = 0;
 PageController _pageController;

 Widget _buildItem(activeIndex, index) {
 final items = widget.items;

 return Center(
 child: AnimatedContainer(
 curve: Curves.easeInOut,
 duration: Duration(milliseconds: 300),
 height: activeIndex == index ? 500.0 : 450.0,
 margin: EdgeInsets.symmetric(vertical: 20.0, horizontal: 10.0),
 decoration: BoxDecoration(
  color: items[index].color,
  borderRadius: BorderRadius.all(Radius.circular(12.0)),
 ),
 child: Stack(
  fit: StackFit.expand,
  children: <Widget>[
  ClipRRect(
  borderRadius: BorderRadius.all(
  Radius.circular(12.0),
  ),
  child: Image.network(
  items[index].image,
  fit: BoxFit.cover,
  ),
  ),
  Align(
  alignment: Alignment.bottomCenter,
  child: Row(
  children: <Widget>[
   Expanded(
   child: Container(
   padding: EdgeInsets.all(12.0),
   decoration: BoxDecoration(
   color: Colors.black26,
   borderRadius: BorderRadius.only(
    bottomRight: Radius.circular(12.0),
    bottomLeft: Radius.circular(12.0),
   ),
   ),
   child: Text(
   items[index].title,
   textAlign: TextAlign.center,
   style: TextStyle(
    fontSize: 20.0,
    fontWeight: FontWeight.bold,
    color: Colors.white,
   ),
   ),
   ),
   )
  ],
  ),
  ),
  ],
 ),
 ),
 );
 }

 @override
 void initState() {
 super.initState();
 _pageController = PageController(
 initialPage: 0,
 viewportFraction: 0.8,
 );
 }

 @override
 Widget build(BuildContext context) {
 return Column(
 children: <Widget>[
 Container(
  height: widget.height,
  child: PageView.builder(
  pageSnapping: true,
  itemCount: heroes.length,
  controller: _pageController,
  onPageChanged: (int index) {
  setState(() {
  _pageIndex = index;
  });
  },
  itemBuilder: (BuildContext ctx, int index) {
  return _buildItem(_pageIndex, index);
  },
  ),
 ),
 PageIndicator(_pageIndex, widget.items.length),
 ],
 );
 }
}

class PageIndicator extends StatelessWidget {
 final int currentIndex;
 final int pageCount;

 const PageIndicator(this.currentIndex, this.pageCount);

 Widget _indicator(bool isActive) {
 return Container(
 width: 6.0,
 height: 6.0,
 margin: EdgeInsets.symmetric(horizontal: 3.0),
 decoration: BoxDecoration(
 color: isActive ? Color(0xff666a84) : Color(0xffb9bcca),
 shape: BoxShape.circle,
 boxShadow: [
  BoxShadow(
  color: Colors.black12,
  offset: Offset(0.0, 3.0),
  blurRadius: 3.0,
  ),
 ],
 ),
 );
 }

 List<Widget> _buildIndicators() {
 List<Widget> indicators = [];
 for (int i = 0; i < pageCount; i++) {
 indicators.add(i == currentIndex ? _indicator(true) : _indicator(false));
 }
 return indicators;
 }

 @override
 Widget build(BuildContext context) {
 return Row(
 mainAxisAlignment: MainAxisAlignment.center,
 children: _buildIndicators(),
 );
 }
}

class IndexPage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return Scaffold(
 appBar: AppBar(
 elevation: 0.0,
 backgroundColor: Colors.white,
 ),
 body: Carousel(
 height: 540,
 items: heroes,
 ),
 backgroundColor: Colors.white,
 );
 }
}

至此,整個(gè)布局就完成了! :sunglasses:

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論