Flutter之banner實現
阿新 • • 發佈:2020-12-12
先寫一個banner控制元件
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:transparent_image/transparent_image.dart'; //這個是在網路上找的一個例子,練手 const MAX_COUNT = 0x7fffffff; /// /// Item的點選事件 /// typedef void OnBannerItemClick(int position, BannerItem entity); /// /// 自定義ViewPager的每個頁面顯示 /// typedef Widget CustomBuild(int position, BannerItem entity); class BannerWidget extends StatefulWidget { final double height; final List<BannerItem> datas; int duration; double pointRadius; Color selectedColor; Color unSelectedColor; Color textBackgroundColor; bool isHorizontal; OnBannerItemClick bannerPress; CustomBuild build; BannerWidget(double this.height, List<BannerItem> this.datas, {Key key, int this.duration = 5000, double this.pointRadius = 3.0, Color this.selectedColor = Colors.red, Color this.unSelectedColor = Colors.white, Color this.textBackgroundColor = const Color(0x99000000), bool this.isHorizontal = true, OnBannerItemClick this.bannerPress, CustomBuild this.build}) : super(key: key); @override BannerState createState() { return new BannerState(); } } class BannerState extends State<BannerWidget> { Timer timer; int selectedIndex = 0; PageController controller; @override void initState() { double current = widget.datas.length > 0 ? (MAX_COUNT / 2) - ((MAX_COUNT / 2) % widget.datas.length) : 0.0; controller = PageController(initialPage: current.toInt()); _initPageAutoScroll(); super.initState(); } _initPageAutoScroll() { start(); } @override void didUpdateWidget(BannerWidget oldWidget) { super.didUpdateWidget(oldWidget); } start() { stop(); timer = Timer.periodic(Duration(milliseconds: widget.duration), (timer) { if(widget.datas.length > 0 && controller != null && controller.page != null) { controller.animateToPage(controller.page.toInt() + 1, duration: Duration(milliseconds: 300), curve: Curves.linear); } }); } stop() { timer?.cancel(); timer = null; } @override void dispose() { stop(); super.dispose(); } @override Widget build(BuildContext context) { return new Container( height: widget.height, color: Colors.black12, child: Stack( children: <Widget>[ getViewPager(), new Align( alignment: Alignment.bottomCenter, child: IntrinsicHeight( child: Container( padding: EdgeInsets.all(6.0), color: widget.textBackgroundColor, child: getBannerTextInfoWidget(), ), ), ), ], ), ); } Widget getViewPager() { return PageView.builder( itemCount: widget.datas.length > 0 ? MAX_COUNT : 0, controller: controller, onPageChanged: onPageChanged, itemBuilder: (context, index) { return InkWell( onTap: () { if (widget.bannerPress != null) widget.bannerPress(selectedIndex, widget.datas[selectedIndex]); }, child: widget.build == null ? FadeInImage.memoryNetwork( placeholder: kTransparentImage, image: widget.datas[index % widget.datas.length].itemImagePath, fit: BoxFit.cover) : widget.build( index, widget.datas[index % widget.datas.length])); }, ); } Widget getSelectedIndexTextWidget() { return widget.datas.length > 0 && selectedIndex < widget.datas.length ? widget.datas[selectedIndex].itemText : Text(''); } Widget getBannerTextInfoWidget() { if (widget.isHorizontal) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ new Expanded( flex: 1, child: getSelectedIndexTextWidget(), ), Expanded( flex: 0, child: Row( mainAxisSize: MainAxisSize.min, children: circle(), ), ), ], ); } else { return new Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ getSelectedIndexTextWidget(), IntrinsicWidth( child: Row( children: circle(), ), ), ], ); } } List<Widget> circle() { List<Widget> circle = []; for (var i = 0; i < widget.datas.length; i++) { circle.add(Container( margin: EdgeInsets.all(2.0), width: widget.pointRadius * 2, height: widget.pointRadius * 2, decoration: new BoxDecoration( shape: BoxShape.circle, color: selectedIndex == i ? widget.selectedColor : widget.unSelectedColor, ), )); } return circle; } onPageChanged(index) { selectedIndex = index % widget.datas.length; setState(() {}); } } class BannerItem { String itemImagePath; Widget itemText; static BannerItem defaultBannerItem(String image, String text) { BannerItem item = new BannerItem(); item.itemImagePath = image; Text textWidget = new Text( text, softWrap: true, maxLines: 3, overflow: TextOverflow.ellipsis, style: TextStyle( color: Colors.white, fontSize: 12.0, decoration: TextDecoration.none), ); item.itemText = textWidget; return item; } }
去網上搞資料填充資料
import 'package:dio/dio.dart'; const String BASEURL ="https://www.wanandroid.com"; class HttpConfig{ static const baseUrl = BASEURL; static const timeout = 3000; } class RequestManager{ static final BaseOptions options = BaseOptions( baseUrl: HttpConfig.baseUrl,connectTimeout: HttpConfig.timeout ); static final Dio dio = Dio(options); static Future<T> request<T>(String url,{String method='get',Map<String,dynamic> params,Interceptor interceptor})async{ final options = Options(method:method); Interceptor dInter = InterceptorsWrapper( onRequest: (RequestOptions options){ return options;// }, onResponse: (Response response){ return response; }, onError:(DioError error){ return error; } ); List<Interceptor> inters = [dInter]; if(interceptor!=null){ inters.add(interceptor); } dio.interceptors.addAll(inters); //傳送網路請求 try{ Response response = await dio.request<T>(url,queryParameters: params,options: options); return response.data; }on DioError catch(e){ return Future.error(e); } } }
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_weight_ui/model/home_banner_data_entity.dart'; import 'banner_widget.dart'; import '../net/RequestUtils.dart'; class BannerPage extends StatefulWidget{ @override State<StatefulWidget> createState() =>_BannerPage(); } class _BannerPage extends State<BannerPage>{ List<HomeBannerDataData> data = new List<HomeBannerDataData>(); List<BannerItem> datas = []; @override void initState() { getHomeData(); super.initState(); } getHomeData() async { var result = await RequestManager.request("https://www.wanandroid.com/banner/json"); setState(() { HomeBannerDataEntity dataBean = HomeBannerDataEntity().fromJson(result); data.addAll(dataBean.data); for(var i=0;i<data.length;i++){ datas.add(BannerItem.defaultBannerItem(data[i].imagePath, data[i].title)); } }); } @override Widget build(BuildContext context) { return Scaffold( appBar: new AppBar( centerTitle: true, title: Text('首頁'), ), body: Center( child: Column( children: <Widget>[ new BannerWidget( 180.0, datas, bannerPress: (pos, item) { //TODO去做特別的邏輯 }, ) ], ), ), ); } }
用到的庫,以及JsonToDartBean外掛(自行百度)
dependencies:
flutter:
sdk: flutter
dio: ^3.0.9
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.0
transparent_image: ^0.1.0