內容: 1、列表展示 2、輪播圖 3、其他 本次的內容也是在上一節的基礎上進行操作 我們就搞這個story模塊。 目錄: story.dart story主頁面 story_item.dart 構造列表頁面 裡面涉及到兩個公共庫 touch_callback.dart 觸摸回調 story_data ...
內容:
1、列表展示
2、輪播圖
3、其他
本次的內容也是在上一節的基礎上進行操作
我們就搞這個story模塊。
目錄:
story.dart story主頁面
import 'package:flutter/material.dart'; import 'story_data.dart'; import 'story_item.dart'; void main() => runApp(Story()); class Story extends StatefulWidget { @override _Story createState() => new _Story(); } class _Story extends State<Story> { @override Widget build(BuildContext context) { // TODO: implement build return Scaffold( body: ListView.builder( itemCount: storyData.length, // 構造列表項 itemBuilder: (BuildContext context, int index) { // 傳入MessageData返回列表項 return new StoryItem(storyData[index]); }, ), ); } }
story_item.dart 構造列表頁面
import 'package:flutter/material.dart'; import 'story_data.dart'; import 'package:date_format/date_format.dart'; import '../common/touch_callback.dart'; import 'story_content.dart'; class StoryItem extends StatelessWidget { final StoryData story; StoryItem(this.story); void main(){ print(this.story); } @override Widget build(BuildContext context) { // TODO: implement build return Container( decoration: BoxDecoration( color: Colors.white, // 底部邊 border: Border(bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9))), ), height: 64.0, // 按下回調處理空實現 child: TouchCallBack( child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ // 展示頭像 Container( // 頭像左右留一定外邊距 margin: const EdgeInsets.only(left: 13.0, right: 13.0), child: Image.asset(story.image, width: 48.0, height: 48.0,), ), Expanded( // 主標題和子標題採用垂直佈局image/message_normal.png child: Column( // 垂直方向居中佈局 mainAxisAlignment: MainAxisAlignment.center, // 水平方向靠左對齊 crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Text( story.title, style: TextStyle(fontSize: 16.0, color:Color(0xFF353535)), maxLines: 1, ), Padding( padding: const EdgeInsets.only(top: 8.0), ), Text( story.subTitle, style: TextStyle(fontSize: 14.0, color:Color(0xFF9a9a9a)), maxLines: 1, // 顯示不完的文本用省略號來顯示 overflow: TextOverflow.ellipsis, ), ], ), ), ], ), onPressed: () { // 跳轉到新的頁面 Navigator.push(context, new MaterialPageRoute(builder: (BuildContext context){ return new StoryContent(story); })); }, ), ); } }
裡面涉及到兩個公共庫
touch_callback.dart 觸摸回調
import 'package:flutter/material.dart'; // 觸摸回調組件 class TouchCallBack extends StatefulWidget{ // 子組件 final Widget child; // 回調函數 final VoidCallback onPressed; final bool isfeed; // 背景色 final Color background; // 傳入參數列表 TouchCallBack({Key key, @required this.child, @required this.onPressed, this.isfeed:true, this.background:const Color(0xffd8d8d8), }):super(key: key); @override TouchState createState() => TouchState(); } class TouchState extends State<TouchCallBack> { Color color = Colors.transparent; @override Widget build(BuildContext context) { // TODO: implement build // 返回GestureDetector return GestureDetector( // 使用container容器包裹 child: Container( color: color, child: widget.child, ), // onTap 回調 onTap: widget.onPressed, onPanDown: (d) { if(widget.isfeed == false) return; setState(() { color = widget.background; }); }, onPanCancel: () { setState(() { color = Colors.transparent; }); }, ); } }
story_data.dart 模擬數據
// 聊天數據 class StoryData { // id var id; // 頭像 String image; // 主標題 String title; // 副標題 String subTitle; // 描述 String description; // 圖集 List imageList; StoryData( this.id, this.image, this.title, this.subTitle , this.description, this.imageList); } List<StoryData> storyData = [ new StoryData( 1, 'images/story/01/cover.jpg', 'episode.1', 'プロローグ', '因為黑沼爽子的外表看起來很陰沉,所以大家給她取了個“貞子”的外號,對想跟大家打成一片的爽子來說,個性開朗活潑又是大家中心人物的風早翔太就成了爽子心中憧憬的對象。在結業式前,爽子心中憧憬的對象風早約了爽子參加試膽大會。', [ 'images/story/01/01.jpg', 'images/story/01/02.jpg', 'images/story/01/03.jpg', 'images/story/01/04.jpg', 'images/story/01/05.jpg', 'images/story/01/06.jpg', ] ), new StoryData( 2, 'images/story/02/cover.jpg', 'episode.2', '席替え', '在大雨中淋的全身濕透的爽子到了學校,看到她這幅模樣的同學們都感到無比的害怕,但是卻因為這個機會,讓爽子和吉田千鶴,矢野有了說話的機會,而爽子也很感謝風早很溫柔的對待她。爽子也決定要趁這次換座位的機會下定決心要和坐在隔壁的同學好好相處,可是…。', [ 'images/story/02/01.jpg', 'images/story/02/02.jpg', 'images/story/02/03.jpg', 'images/story/02/04.jpg', 'images/story/02/05.jpg', ] ), new StoryData( 3, 'images/story/03/cover.jpg', 'episode.3', '放課後', '終於可以和自己憧憬的同學自然的說早安。正當爽子正在為這件事感動的時候,這學期代理班導的副班導荒井一市(通稱:阿瓶)登場了,阿瓶正想要擅自決定誰來製作出席簿時,不想看到大家困擾的爽子就舉起了手…。', [] ), new StoryData( 4, 'images/story/04/cover.jpg', 'episode.4', '噂', '因為千鶴和矢野的關係,爽子終於再次嘗到幸福的滋味。可是在學校中突然開始傳出中傷千鶴和矢野的流言。雖然千鶴和矢野一開始聽到傳出謠言的人是爽子的時候是一笑置之不太相信,可是…。', [] ), new StoryData( 5, 'images/story/05/cover.jpg', 'episode.5', '決意', '爽子以為千鶴和矢野的流言是因為自己的關係,而感到自責,所以為了不要再讓千鶴和矢野受到傷害,決定回到獨來獨往的自己,而且也和風早保持距離以免風早也受到牽連。但是千鶴和矢野卻被爽子突然冷漠的態度感到迷惘,一直拚命想找出答案。而風早則為了確定爽子的心意決定直接找上爽子…。', [] ), new StoryData( 6, 'images/story/06/cover.jpg', 'episode.6', '友達', '爽子無意間在女生廁所內聽到同年級的在談論千鶴和矢野的謠言,爽子為了要澄清誤會,卻引起了大騒動,連爽子的同班同學們也都說謠言是爽子傳的,但是卻遭到風早強烈的否定。就在這個時候千鶴和矢野登場了…。', [] ) ];
story_content.dart 故事詳情
import 'package:flutter/material.dart'; import 'story_data.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:carousel_slider/carousel_slider.dart'; //import 'dart:math'; class StoryContent extends StatefulWidget { final StoryData story; StoryContent(this.story); // StoryContent({Key key}) : super(key: key); @override _StoryContent createState() => new _StoryContent(story); } class _StoryContent extends State<StoryContent> { // 獲取參數story final StoryData story; _StoryContent(this.story); String number = '124'; String defaultIcon = '0'; void main() { print(1); } void _change() { setState(() { number = defaultIcon == '0'? (int.parse(number) + 1).toString(): (int.parse(number) - 1).toString(); defaultIcon = defaultIcon == '0' ? '1': '0'; }); print(story.imageList); } @override Widget build(BuildContext context) { ScreenUtil.instance = ScreenUtil(width: 750, height: 1334)..init(context); // TODO: implement build return Scaffold( appBar: new AppBar( leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: () { Navigator.pop(context); // 返回 } ), ), body: new Container( alignment: Alignment.center, decoration: BoxDecoration( image: DecorationImage( image: AssetImage('images/bg/flower_one.jpg'), fit: BoxFit.cover, )), child: new Column( crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ new Container( alignment: Alignment.center, width: double.infinity, margin: const EdgeInsets.only(top: 30.0, bottom: 10.0), child: Text( story.title + story.subTitle, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 20.0, ), ), ), new Container( decoration: new BoxDecoration( border: new Border.all(width: 1.0, color: Colors.pink), color: Colors.grey, borderRadius: new BorderRadius.all(new Radius.circular(4.0)), ), width: ScreenUtil().setWidth(700), child: story.imageList.length != 0 ? new CarouselSlider( items: story.imageList.map((i) { return new Builder( builder: (BuildContext context) { return new Container( width: MediaQuery.of(context).size.width , // margin: new EdgeInsets.only(left: 0, right: 1.0), decoration: new BoxDecoration( color: Colors.amber ), child: new Image.asset( i, fit: BoxFit.fill, ), ); }, ); }).toList(), height: 180.0, autoPlay: false ) : Image.asset(story.image, fit:BoxFit.fill), ), new Container( margin: const EdgeInsets.only(top: 10.0, bottom: 10.0), alignment: Alignment.center, width: ScreenUtil().setWidth(700), child: Text( story.description, style: TextStyle( letterSpacing: 2.0, // wordSpacing: 15.0, ), ), ), // 收藏 new Container( margin: const EdgeInsets.only(top: 4.0, bottom: 10.0), alignment: Alignment.bottomCenter, width: ScreenUtil().setWidth(700), child: new Row( children: <Widget>[ new IconButton( icon: defaultIcon == '0' ? const Icon(Icons.favorite_border, color: Colors.red) : const Icon(Icons.favorite, color: Colors.red), onPressed: _change, ), new Text( number.toString(), ), ], ), ) ], ), ), ); } }
輪播插件
使用方法:
import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; class Page2 extends StatelessWidget { final imagesList = [ 'xxxx.jpg', 'xxxx1.jpg', 'xxxx1.jpg', ] @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text("carousel"), ), body: new CarouselSlider( items: imagesList.map((image) { return new Builder( builder: (BuildContext context) { return new Container( width: MediaQuery.of(context).size.width, decoration: new BoxDecoration( color: Colors.amber ), child: new Image.assert( image fit: BoxFit.fill, ) ); }, ); }).toList(), height: 180.0, autoPlay: false //自動播放 ) ); } }
這裡有個註意的地方,實時更新數據,渲染頁面
setState(() { number = defaultIcon == '0'? (int.parse(number) + 1).toString(): (int.parse(number) - 1).toString(); defaultIcon = defaultIcon == '0' ? '1': '0'; });
截圖: