直播带货源码,flutter 顶部滚动栏+页面
直播带货源码,flutter 顶部滚动栏+页面
tabPage.dart
1 | <br>import 'package:flutter/cupertino.dart' ;<br>import 'package:flutter/material.dart' ;<br>import 'package:flutter_trip/dao/travelDao.dart' ;<br>import 'package:flutter_trip/model/home/commonModel.dart' ;<br>import 'package:flutter_trip/model/travel/travelModel.dart' ;<br>import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart' ;<br>import 'package:flutter_trip/widget/applicationWebView.dart' ;<br>import 'package:flutter_trip/widget/loadingContainer.dart' ;<br> <br> const _TRAVEL_URL =<br> 'https://m.ctrip.com/restapi/soa2/16189/json/searchTripShootListForHomePageV2?_fxpcqlniredt=09031014111431397988&__gw_appid=99999999&__gw_ver=1.0&__gw_from=10650013707&__gw_platform=H5' ;<br> const PAGE_SIZE = 10;<br> <br> class TabPage extends StatefulWidget {<br> final String travelUrl;<br> final String channelCode;<br> <br> TabPage({Key? key, required this.travelUrl, required this.channelCode})<br> : super(key: key);<br> <br> @override<br> State<StatefulWidget> createState() {<br> // TODO: implement createState<br> return _TabPageState();<br> }<br>}<br> <br> class _TabPageState extends State<TabPage> with AutomaticKeepAliveClientMixin {<br> List<TravelItem> travelItem = [];<br> int pageIndex = 0;<br> bool isLoad = true;<br> <br> ScrollController _scrollController = ScrollController();<br> <br> @override<br> // TODO: implement wantKeepAlive<br> bool get wantKeepAlive => true;<br> <br> @override<br> void initState() {<br> // TODO: implement initState<br> super.initState();<br> _loadData();<br> <br> _scrollController.addListener(() {<br> if (_scrollController.position.pixels ==<br> _scrollController.position.maxScrollExtent) {<br> _loadData(loadMore: true);<br> print ( "滚动到最底部有" );<br> }<br> });<br> }<br> <br> @override<br> Widget build(BuildContext context) {<br> // TODO: implement build<br> return Scaffold(<br> body: LoadingContainer(<br> isLoading: isLoad,<br> cover: true,<br> child: RefreshIndicator(<br> onRefresh: _handleRefresh,<br> child: MediaQuery.removePadding(<br> removeTop: true,<br> context: context,<br> child: new StaggeredGridView.countBuilder(<br> controller: _scrollController,<br> crossAxisCount: 2,<br> itemCount: travelItem.length,<br> itemBuilder: (BuildContext context, int index) =><br> _TraveItem(index: index, item: travelItem[index]),<br> staggeredTileBuilder: (int index) => new StaggeredTile.fit(1),<br> // mainAxisSpacing: 4.0,<br> // crossAxisSpacing: 4.0,<br> ),<br> ),<br> ),<br> ),<br> );<br> }<br> <br> Future<void> _handleRefresh() async {<br> _loadData();<br> }<br> <br> _loadData({bool loadMore = false}) {<br> if (loadMore) {<br> pageIndex++;<br> } else {<br> pageIndex = 0;<br> }<br> <br> TravelDao.fetch(widget.travelUrl, widget.channelCode, pageIndex, PAGE_SIZE)<br> .then((value) {<br> setState(() {<br> List<TravelItem> items = _filterItems(value.resultList);<br> if (travelItem.length != 0) {<br> travelItem.addAll(items);<br> } else {<br> travelItem = items;<br> }<br> isLoad = false;<br> });<br> }).catchError((onError) {<br> print ( '网络请求出错 $onError' );<br> });<br> }<br> <br> List<TravelItem> _filterItems(List<TravelItem>? resultList) {<br> List<TravelItem> items = [];<br> if (resultList != null) {<br> resultList.forEach((element) {<br> if (element.article != null) {<br> items.add(element);<br> }<br> });<br> }<br> return items;<br> }<br>}<br> <br> class _TraveItem extends StatelessWidget {<br> final int index;<br> final TravelItem item;<br> _TraveItem({Key? key, required this.index, required this.item})<br> : super(key: key);<br> <br> @override<br> Widget build(BuildContext context) {<br> // TODO: implement build<br> return GestureDetector(<br> onTap: () {<br> if (item.article.urls.length > 0) {<br> // Navigator.push(<br> // context,<br> // MaterialPageRoute(<br> // builder: (context) => ApplicationWebView(<br> // commonModel: CommonModel(<br> // icon: '' ,<br> // title: '详情' ,<br> // url: item.article.urls[0].h5Url,<br> // statusBarColor: 'ffffff' ,<br> // hideAppBar: false),<br> // )));<br> }<br> },<br> child: Card(<br> child: PhysicalModel(<br> color: Colors.transparent,<br> clipBehavior: Clip.antiAlias,<br> borderRadius: BorderRadius.circular(5),<br> child: Column(<br> crossAxisAlignment: CrossAxisAlignment.start,<br> children: [<br> _itemImage(),<br> Container(<br> padding: EdgeInsets.all(4),<br> child: Text(<br> item.article.articleTitle,<br> textAlign: TextAlign.left,<br> maxLines: 2,<br> overflow: TextOverflow.ellipsis,<br> style: TextStyle(fontSize: 14, color: Colors.black),<br> ),<br> ),<br> _infoText(),<br> ],<br> ),<br> ),<br> ),<br> );<br> }<br> <br> _itemImage() {<br> return Stack(<br> children: [<br> Image.network(item.article.images[0].dynamicUrl),<br> Positioned(<br> bottom: 8,<br> left: 8,<br> child: Container(<br> padding: EdgeInsets.fromLTRB(5, 1, 5, 1),<br> decoration: BoxDecoration(<br> color: Colors.black54,<br> borderRadius: BorderRadius.circular(10),<br> ),<br> child: Row(<br> mainAxisAlignment: MainAxisAlignment.center,<br> children: [<br> Icon(<br> Icons.location_on_outlined,<br> size: 12,<br> color: Colors.white,<br> ),<br> LimitedBox(<br> maxWidth: 130,<br> child: Text(<br> _positonName(),<br> maxLines: 1,<br> overflow: TextOverflow.ellipsis,<br> style: TextStyle(fontSize: 12, color: Colors.white),<br> ),<br> )<br> ],<br> ),<br> ),<br> )<br> ],<br> );<br> }<br> <br> String _positonName() {<br> // return item.article.pois?.length == 0<br> // ? '未知' <br> // : item.article.pois![0]!.poiName;<br> return item.article.pois?.length == 0<br> ? '未知' <br> : item.article.pois![0]?.poiName ?? '未知' ;<br> }<br> <br> _infoText() {<br> return Container(<br> padding: EdgeInsets.fromLTRB(6, 0, 6, 10),<br> child: Row(<br> mainAxisAlignment: MainAxisAlignment.spaceBetween,<br> children: [<br> Row(<br> children: [<br> PhysicalModel(<br> color: Colors.transparent,<br> clipBehavior: Clip.antiAlias,<br> borderRadius: BorderRadius.circular(12),<br> child: Image.network(<br> item.article.author!.coverImage!.dynamicUrl,<br> width: 24,<br> height: 24,<br> ),<br> ),<br> Container(<br> width: 90,<br> padding: EdgeInsets.all(5),<br> child: Text(<br> item.article.author!.nickName,<br> textAlign: TextAlign.left,<br> style: TextStyle(fontSize: 12),<br> maxLines: 1,<br> overflow: TextOverflow.ellipsis,<br> ),<br> )<br> ],<br> ),<br> Row(<br> mainAxisAlignment: MainAxisAlignment. end ,<br> children: [<br> Icon(<br> Icons.thumb_up,<br> color: Colors.grey,<br> size: 12,<br> ),<br> Container(<br> padding: EdgeInsets.only(left: 3),<br> child: Text(<br> item.article.likeCount.toString(),<br> maxLines: 1,<br> style: TextStyle(<br> color: Colors.grey,<br> fontSize: 10,<br> ),<br> ),<br> )<br> ],<br> )<br> ],<br> ),<br> );<br> }<br>} |
tabTravel.dart
1 | <br>import 'package:flutter/material.dart' ;<br>import 'package:flutter_trip/dao/travelDao.dart' ;<br>import 'package:flutter_trip/dao/travelTabDao.dart' ;<br>import 'package:flutter_trip/model/travel/travelModel.dart' ;<br>import 'package:flutter_trip/model/travel/travelTabModel.dart' ;<br>import 'package:flutter_trip/pages/travel/tabPage.dart' ;<br> <br> class TabTravel extends StatefulWidget {<br> @override<br> _TabTravelState createState() => _TabTravelState();<br>}<br> <br> class _TabTravelState extends State<TabTravel><br> with SingleTickerProviderStateMixin {<br> late TabController tabController;<br> late TravelTabModel travelTabModel;<br> <br> bool isInit = false;<br> List<TravelTab> tabs = [];<br> <br> @override<br> void initState() {<br> //tabController = TabController(length: 0, vsync: this);<br> // TODO: implement initState<br> super.initState();<br> TravelTabDao.fetch().then((TravelTabModel tabModel) {<br> tabController = TabController(length: tabModel.tabs.length, vsync: this);<br> <br> setState(() {<br> tabs = tabModel.tabs;<br> travelTabModel = tabModel;<br> });<br> this.isInit = true;<br> }).catchError((error) {<br> print("error $error");<br> });<br> }<br> <br> @override<br> Widget build(BuildContext context) {<br> // TODO: implement build<br> return Scaffold(<br> body: Column(<br> children: [<br> isInit<br> ? Container(<br> color: Colors.white,<br> padding:<br> EdgeInsets.only(top: MediaQuery.of(context).padding.top),<br> child: TabBar(<br> padding: EdgeInsets.zero,<br> controller: tabController,<br> isScrollable: true,<br> labelColor: Colors.black87,<br> labelPadding: EdgeInsets.only(left: 20, right: 20),<br> indicator: UnderlineTabIndicator(<br> borderSide: BorderSide(<br> color: Colors.lightBlue,<br> width: 3,<br> ),<br> insets: EdgeInsets.only(bottom: 10),<br> ),<br> tabs:<br> tabs.map((item) => Tab(text: item.labelName)).toList(),<br> ),<br> )<br> : Container(),<br> Flexible(<br> child: isInit<br> ? TabBarView(<br> controller: tabController,<br> children: tabs<br> .map((item) => TabPage(<br> travelUrl: travelTabModel.url,<br> channelCode: item.groupChannelCode))<br> .toList(),<br> // children: tabs<br> // .map((item) => Tab(text: item.groupChannelCode))<br> // .toList(),<br> )<br> : Container(),<br> )<br> ],<br> ),<br> );<br> }<br> <br> @override<br> void dispose() {<br> // TODO: implement dispose<br> tabController.dispose();<br> super.dispose();<br> } |
以上就是 直播带货源码,flutter 顶部滚动栏+页面,更多内容欢迎关注之后的文章
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2022-03-03 短视频系统源码,点开图片双指放大或双击放大
2022-03-03 直播软件开发,同一分类下仅状态栏切换有无特效两个版本
2022-03-03 直播软件搭建,横版自动滑动的轮播图