import 'package:cached_network_image/cached_network_image.dart'; import 'package:chat/data/UserData.dart'; import 'package:chat/data/WebData.dart'; import 'package:chat/data/constants.dart'; import 'package:chat/generated/i18n.dart'; import 'package:chat/home/AddProgram.dart'; import 'package:chat/utils/CustomUI.dart'; import 'package:chat/utils/HttpUtil.dart'; import 'package:chat/utils/MessageBox.dart'; import 'package:chat/utils/MessageMgr.dart'; import 'package:chat/utils/PopUpMenu.dart' as myPop; import 'package:chat/utils/TokenMgr.dart'; import 'package:chat/utils/screen.dart'; import 'package:dio/dio.dart'; import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart' as myExt; import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart'; import 'package:flutter/material.dart'; import 'package:flutter_swiper/flutter_swiper.dart'; import 'package:chat/utils/DropDownMemu.dart'; import 'package:oktoast/oktoast.dart'; import 'package:url_launcher/url_launcher.dart'; const ChinaKey = 'China-ChinaRepeat'; class SortCondition { String key; String name; bool isSelected; SortCondition({this.name, this.isSelected, this.key}); } class ParkPage extends StatefulWidget { final int searchType; ParkPage({Key key, this.searchType = -1}) : super(key: key); _ParkPageState createState() => _ParkPageState(); } class _ParkPageState extends State { List _dropDownHeaderItemStrings = []; List _sexSortCondition = []; List _timeSortConditions = []; SortCondition _selectSexSortCondition; SortCondition _selectTimeSortCondition; ScrollController _scrollController = new ScrollController(); GlobalKey _key = GlobalKey(); bool isLoadingFinish = false; List bannerImages = []; String timeCat = '1'; String search = '1'; String guid = ''; bool isLoading = false; //是否正在加载数据 int _page = 1; int rows = 20; bool isHomePage = true; bool isOnline = false; bool loadSuccess = false; List list = []; GlobalKey _stackKey = GlobalKey(); GZXDropdownMenuController _dropdownMenuController = GZXDropdownMenuController(); initValues() { if (!loadSuccess) { _dropDownHeaderItemStrings = [ I18n.of(context).release_time, I18n.of(context).any_sex, UserData().isInChina ? WebData().provinces['China'] : I18n.of(context).unlimited_area ]; search = UserData().isInChina ? ChinaKey : '1'; _sexSortCondition = [ SortCondition( key: '0', name: I18n.of(context).any_sex, isSelected: true), SortCondition( key: '2', name: I18n.of(context).look_women, isSelected: false), SortCondition( key: '1', name: I18n.of(context).look_men, isSelected: false) ]; _selectSexSortCondition = _sexSortCondition[0]; _timeSortConditions.add(SortCondition( key: '1', name: I18n.of(context).release_time, isSelected: true)); _timeSortConditions.add(SortCondition( key: '2', name: I18n.of(context).activity_time, isSelected: false)); _selectTimeSortCondition = _timeSortConditions[0]; loadSuccess = true; getNewData(); setState(() {}); } } //获取新的数据 void getData(callback) async { Map data = { "userId": UserData().basicInfo.userId, "time": _selectTimeSortCondition.key, "sex": _selectSexSortCondition.key, "area": search, }; data['sign'] = TokenMgr().getSign(data); data['page'] = _page; data['guid'] = guid; data['rows'] = rows; data['type'] = widget.searchType; data['online'] = isOnline ? 1 : 0; data['lng'] = UserData().longitude; data['lat'] = UserData().latitude; Response res = await HttpUtil().post('station/program/dynamic', data: data); var resData = res.data; isLoadingFinish = true; if (resData['code'] == 0) { guid = resData['data']['guid']; callback(resData['data']['list']); } } void getNewData() { _page = 1; guid = ''; getData((data) { list.clear(); if (data != null) { list.addAll(data); } setState(() {}); }); } @override void dispose() { _scrollController.dispose(); MessageMgr().off('delete_program', msgListDelete); MessageMgr().off('Add_program', addProgramCallback); MessageMgr().off('love_program', msgListLove); MessageMgr().off('refresh_list', msgRefreshList); MessageMgr().off('join_program', msgJoinList); super.dispose(); } //发布添加回调 addProgramCallback(data) { if (list.length > 0 && list[0]['UserId'] == UserData().basicInfo.userId && list[0]['Type'] == 0) { list.insert(1, data); } else { list.insert(0, data); } } getBanner() async { Map data = { "userid": UserData().basicInfo.userId, }; data['sign'] = TokenMgr().getSign(data); Response res = await HttpUtil().post('banner/get/list', data: data); var resData = res.data; if (resData['code'] == 0) { setState(() { bannerImages = resData['data']; }); } } @override void initState() { WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = false; super.initState(); _scrollController.addListener(() { //print('---_scrollController offset: ${_scrollController.offset}'); }); getBanner(); isHomePage = widget.searchType == -1; MessageMgr().on('delete_program', msgListDelete); MessageMgr().on('Add_program', addProgramCallback); MessageMgr().on('love_program', msgListLove); MessageMgr().on('refresh_list', msgRefreshList); MessageMgr().on('join_program', msgJoinList); } msgJoinList(data) { for (int i = 0; i < list.length; i++) { if (list[i]['Id'] == data) { list[i]['EnrollNum']++; list[i]['IsEnroll']++; setState(() {}); break; } } } msgRefreshList(data) { _onRefresh(); } msgListDelete(data) { for (int i = 0; i < list.length; i++) { if (list[i]['Id'] == data) { list.removeAt(i); setState(() {}); break; } } } msgListLove(data) { print('msgListLove $data'); for (int i = 0; i < list.length; i++) { if (list[i]['Id'] == data) { list[i]['FabulousNum']++; list[i]['IsFabulous']++; setState(() {}); break; } } } Future _getMore() async { if (!isLoading) { setState(() { isLoading = true; }); getMoreData(); } } void getMoreData() { _page++; getData((data) { data == null || data.length == 0 ? _page-- : list.addAll(data); isLoading = false; setState(() {}); }); } void addProgram(str) async { if (str == 'program') { //自己是女性,且未认证,提示去认证 if (!UserData().isMan() && !UserData().basicInfo.isAttestation) { CustomUI.buildNotTrue(context); return; } if (!UserData().isCanProgram) { showToast(I18n.of(context).stop_program); } else { Navigator.of(context).push( new MaterialPageRoute( builder: (context) { return AddProgram( isProgram: true, ); }, ), ); } } else if (str == 'dynamic') { //自己是女性,且未认证,提示去认证 if (!UserData().isMan() && !UserData().basicInfo.isAttestation) { CustomUI.buildNotTrue(context); return; } Navigator.of(context).push( new MaterialPageRoute( builder: (context) { return AddProgram( isProgram: false, ); }, ), ); } } @override Widget build(BuildContext context) { initValues(); Color btnColor = isOnline ? Constants.BlueTextColor : Colors.grey[400]; Widget appBar = AppBar( //automaticallyImplyLeading: !isHomePage, title: Text( isHomePage ? I18n.of(context).radio : WebData().getProgramName(context, widget.searchType), textScaleFactor: 1.0, ), leading: CustomUI.buildCustomLeading(context), elevation: 0, actions: [ isHomePage ? myPop.PopupMenuButton( padding: EdgeInsets.zero, offset: Offset(0, 45), child: new Padding( padding: EdgeInsets.only(right: 15, left: 15, top: 20, bottom: 10), child: CircleAvatar( backgroundColor: Constants.GreyBackgroundColor, radius: 13.75, child: Icon( IconData(0xe697, fontFamily: 'iconfont'), color: Constants.BlackTextColor, size: 15, )), ), onSelected: (str) { addProgram(str); }, itemBuilder: (BuildContext context) => >[ myPop.PopupMenuItem( value: 'program', child: Container( margin: EdgeInsets.only(top: 15, bottom: 15), child: Text( I18n.of(context).release_program, textScaleFactor: 1.0, textAlign: TextAlign.center, ), )), myPop.PopupMenuDivider( height: 1, ), myPop.PopupMenuItem( value: 'dynamic', child: Container( margin: EdgeInsets.only(top: 15, bottom: 15), child: Text( I18n.of(context).release_dynamics, textScaleFactor: 1.0, textAlign: TextAlign.center, )), ), ], ) : GestureDetector( child: Container( alignment: Alignment.center, margin: EdgeInsets.only(top: 15, bottom: 10, right: 10), child: Text(I18n.of(context).first_online, textScaleFactor: 1.0, style: TextStyle(color: btnColor, fontSize: 13), textAlign: TextAlign.center), padding: EdgeInsets.only(left: 20, right: 20), decoration: BoxDecoration( border: Border.all(color: btnColor, width: 1), borderRadius: BorderRadius.all(Radius.circular(5.0))), ), onTap: () { setState(() { isOnline = !isOnline; getNewData(); }); }, ), ], centerTitle: true, ); return Scaffold( body: SafeArea( child: Center( child: Container( height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width, child: _buildBody(), ), )), appBar: appBar, ); } Future _onRefresh() async { getNewData(); } //分类按钮 Widget _buildCategoryButton() { return Container( padding: EdgeInsets.only(top: 10), child: Column( children: [ Container( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildIconButton(1, WebData().getProgramName(context, 0), Constants.Category1Color, 0), _buildIconButton(2, WebData().getProgramName(context, 1), Constants.Category2Color, 1), _buildIconButton(3, WebData().getProgramName(context, 2), Constants.Category3Color, 2), _buildIconButton(4, WebData().getProgramName(context, 3), Constants.Category4Color, 3), ], ), ), Container( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildIconButton(5, WebData().getProgramName(context, 4), Constants.Category5Color, 4), _buildIconButton(6, WebData().getProgramName(context, 5), Constants.Category6Color, 5), _buildIconButton(7, WebData().getProgramName(context, 6), Constants.Category7Color, 6), _buildIconButton(8, WebData().getProgramName(context, 7), Constants.Category8Color, 7), ], ), ), ], )); } Widget _buildIconButton(iconNum, str, strColor, value) { Widget icon = Container( padding: EdgeInsets.only(left: 10, right: 10, bottom: 8), child: Image.asset( 'assets/images/park/qz_icon$iconNum.png', height: 50, )); Widget text = Positioned( bottom: 0, child: Container( child: new Text(str, textScaleFactor: 1.0, style: TextStyle(color: strColor, fontSize: 11)), )); return InkWell( onTap: () { Navigator.of(context).push( new MaterialPageRoute( builder: (context) { return ParkPage( searchType: value, ); }, ), ); }, highlightColor: Colors.transparent, radius: 0, child: Container( alignment: Alignment.center, width: (MediaQuery.of(context).size.width) / 4, margin: EdgeInsets.only(top: 10), child: Stack( alignment: Alignment.center, children: [ icon, text, ], ), )); } Widget _buildBody() { double height = Screen.width * 0.285 + 205; double headerHeight = 46; Widget header = Container( decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey[350]))), padding: EdgeInsets.only(left: 5, right: 5), child: GZXDropDownHeader( // 下拉的头部项,目前每一项,只能自定义显示的文字、图标、图标大小修改 items: [ GZXDropDownHeaderItem(_dropDownHeaderItemStrings[0]), GZXDropDownHeaderItem(_dropDownHeaderItemStrings[1]), GZXDropDownHeaderItem(_dropDownHeaderItemStrings[2]), ], style: TextStyle(color: Constants.BlackTextColor, fontSize: 12), height: headerHeight, // GZXDropDownHeader对应第一父级Stack的key stackKey: _stackKey, // controller用于控制menu的显示或隐藏 controller: _dropdownMenuController, // 当点击头部项的事件,在这里可以进行页面跳转或openEndDrawer onItemTap: (index) { var nums = height - headerHeight; if (_scrollController.offset < nums) { _scrollController.jumpTo(nums); } }, dividerHeight: 0, borderColor: Colors.white, borderWidth: 0, dropDownStyle: TextStyle(color: const Color(0xFF0368FF), fontSize: 12), )); GZXDropDownMenu menu = GZXDropDownMenu( // controller用于控制menu的显示或隐藏 controller: _dropdownMenuController, // 下拉菜单显示或隐藏动画时长 animationMilliseconds: 150, // 下拉菜单,高度自定义,你想显示什么就显示什么,完全由你决定,你只需要在选择后调用_dropdownMenuController.hide();即可 menus: [ GZXDropdownMenuBuilder( dropDownHeight: 50.0 * _timeSortConditions.length, callback: () { setState(() {}); }, dropDownWidget: _buildConditionListWidget(_timeSortConditions, (value) { _selectTimeSortCondition = value; _dropDownHeaderItemStrings[0] = _selectTimeSortCondition.name; _dropdownMenuController.hide(); isLoadingFinish = false; getNewData(); setState(() {}); })), GZXDropdownMenuBuilder( dropDownHeight: 50.0 * _sexSortCondition.length, callback: () { setState(() {}); }, dropDownWidget: _buildConditionListWidget(_sexSortCondition, (value) { _selectSexSortCondition = value; _dropDownHeaderItemStrings[1] = _selectSexSortCondition.name; _dropdownMenuController.hide(); isLoadingFinish = false; getNewData(); setState(() {}); })), GZXDropdownMenuBuilder( dropDownHeight: 50 * 8.0, callback: () { setState(() {}); }, dropDownWidget: _buildAddressWidget((key, value) { search = key; _dropDownHeaderItemStrings[2] = value; _dropdownMenuController.hide(); isLoadingFinish = false; getNewData(); setState(() {}); })), ], ); var v = Column( children: [ _buildSwiperImageWidget(), _buildCategoryButton(), ], ); var body = myExt.NestedScrollView( key: _key, controller: _scrollController, pinnedHeaderSliverHeightBuilder: () { return headerHeight; }, innerScrollPositionKeyBuilder: () { var index = "Tab"; // index += primaryTC.index.toString(); return Key(index); }, headerSliverBuilder: (BuildContext context, bool boxIsScrolled) { return [ SliverAppBar( pinned: true, automaticallyImplyLeading: false, floating: true, elevation: 0, snap: false, forceElevated: boxIsScrolled, flexibleSpace: FlexibleSpaceBar( collapseMode: CollapseMode.pin, background: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [v], ), ), expandedHeight: (Screen.width * 0.285 + 205), bottom: PreferredSize( preferredSize: Size(double.infinity, headerHeight + 1), child: Stack( key: _stackKey, children: [ header, ], ), ), ) ]; }, body: Center( child: Container( color: Constants.GreyBackgroundColor, child: NotificationListener( onNotification: (scrollNotification) { final maxScroll = scrollNotification.metrics.maxScrollExtent; final currentScroll = scrollNotification.metrics.pixels; if (maxScroll == currentScroll) { _getMore(); } return; }, child: ListView.builder( physics: ClampingScrollPhysics(), itemBuilder: _renderRowNear, itemCount: list.length + 1, ), )), ), ); var newBody = myExt.NestedScrollViewRefreshIndicator( onRefresh: _onRefresh, child: body, ); var body1 = Stack( key: _stackKey, children: [ Container( margin: EdgeInsets.only(top: headerHeight), child: RefreshIndicator( onRefresh: _onRefresh, child: NotificationListener( onNotification: (scrollNotification) { final maxScroll = scrollNotification.metrics.maxScrollExtent; final currentScroll = scrollNotification.metrics.pixels; if (maxScroll == currentScroll) { _getMore(); } return; }, child: ListView.builder( itemBuilder: _renderRowNear, itemCount: list.length + 1, ), ), )), Container( decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey[300])), color: Colors.white, ), child: header, ), ], ); return Stack( children: [ isHomePage ? newBody : body1, menu, isLoadingFinish ? Container() : CustomUI.buildLoaingAnim(context) ], ); } Widget _renderRowNear(BuildContext context, int index) { if ((list == null || list.length == 0) && isLoadingFinish) { return CustomUI.buildNoData(context); //return CustomUI.buildNoData(context); } if (index < list.length) { var userInfo = list[index]; return MessageBox(programInfo: userInfo); } if (list.length > rows * _page) return _getMoreWidget(); return Container(); } Widget _getMoreWidget() { return Center( child: Padding( padding: EdgeInsets.all(10.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( '', style: TextStyle(fontSize: 16.0), ), CircularProgressIndicator( strokeWidth: 1.0, valueColor: AlwaysStoppedAnimation(Constants.BlueTextColor)) ], ), ), ); } //轮播图 Widget _buildSwiperImageWidget() { double width = MediaQuery.of(context).size.width * 0.95; return Container( height: width * 0.3, width: width, decoration: BoxDecoration( borderRadius: BorderRadius.circular(50.0), ), child: (bannerImages == null || bannerImages.length == 0) ? Container() : Swiper( // 初始的时候下标位置 index: 0, /// 无限轮播模式开关 loop: true, itemBuilder: (context, index) { return GestureDetector( onTap: () async { var url = bannerImages[index]['Url']; if (await canLaunch(url)) { await launch(url); } else { throw 'Could not launch $url'; } }, child: Container( child: ClipPath( child: Stack(children: [ Container( width: double.infinity, child: ClipRRect( borderRadius: BorderRadius.circular(10.0), child: CachedNetworkImage( fadeOutDuration: const Duration(milliseconds: 300), fadeInDuration: const Duration(milliseconds: 700), fit: BoxFit.fill, imageUrl: bannerImages[index]['ImgUrl'], placeholder: CustomUI.buildImgLoding, errorWidget: (context, url, error) => new Icon(Icons.error), ), ), ), ]), )), ); }, itemCount: bannerImages.length, /// 设置 new SwiperPagination() 展示默认分页指示器 pagination: SwiperPagination(alignment: Alignment.bottomRight), /// 设置 new SwiperControl() 展示默认分页按钮 // control: SwiperControl(), /// 自动播放开关. autoplay: true, /// 动画时间,单位是毫秒 duration: 300, /// 当用户点击某个轮播的时候调用 onTap: (index) {}, /// 滚动方向,设置为Axis.vertical如果需要垂直滚动 scrollDirection: Axis.horizontal, ), ); } var _selectTempFirstLevelIndex = '1'; var _selectFirstLevelIndex = '1'; var _selectSecondLevelIndex = '-1'; _buildAddressWidget(void itemOnTap(String key, String value)) { List firstLevels = []; if (WebData().provinces.length > 0) { if (UserData().isInChina) { firstLevels .add({'key': 'China', 'value': WebData().provinces['China']}); } else { firstLevels .add({'key': 'VietNam', 'value': WebData().provinces['VietNam']}); } } List secondLevels = []; if (WebData().cities.length > 0) { if (UserData().isInChina) { secondLevels.add( {'key': ChinaKey, 'value': WebData().provinces['China']}); } else { secondLevels .add({'key': '1', 'value': I18n.of(context).unlimited_area}); WebData() .cities['VietNam'] .forEach((k, v) => secondLevels.add({'key': 'VietNam-$k', 'value': v})); } } _selectTempFirstLevelIndex = firstLevels[0]['key']; _selectFirstLevelIndex = firstLevels[0]['key']; _selectSecondLevelIndex = secondLevels[0]['key']; Widget buildRow(item) { var index = item['key']; return GestureDetector( onTap: () { _selectSecondLevelIndex = index; _selectFirstLevelIndex = _selectTempFirstLevelIndex; itemOnTap(index, item['value']); }, child: Container( height: 50, decoration: BoxDecoration( border: Border(top: Constants.GreyBorderSide), ), alignment: Alignment.center, child: Text( item['value'], textScaleFactor: 1.0, style: TextStyle( color: _selectFirstLevelIndex == _selectTempFirstLevelIndex && _selectSecondLevelIndex == index ? const Color(0xFF0368FF) : Constants.BlackTextColor, ), )), ); } return Container( child: Row( children: [ Container( width: MediaQuery.of(context).size.width * 0.4, child: ListView( children: firstLevels.map((item) { var index = item['key']; return GestureDetector( onTap: () { _selectTempFirstLevelIndex = index; if (index == 'China') { itemOnTap(ChinaKey, item['value']); return; } setState(() {}); }, child: Container( height: 50, decoration: BoxDecoration( color: _selectTempFirstLevelIndex == index ? const Color(0xFF0368FF) : Colors.white, border: Border(top: Constants.GreyBorderSide), ), alignment: Alignment.center, child: Text( item['value'], textScaleFactor: 1.0, style: TextStyle( color: _selectTempFirstLevelIndex == index ? Colors.white : Constants.BlackTextColor, ), ))); }).toList(), ), ), Expanded( child: Container( width: double.infinity, decoration: BoxDecoration(border: Border(left: Constants.GreyBorderSide)), child: ListView( children: secondLevels.map((item) { return buildRow(item); }).toList(), ), ), ) ], )); } _buildConditionListWidget(items, void itemOnTap(sortCondition)) { return ListView.separated( shrinkWrap: true, scrollDirection: Axis.vertical, physics: const NeverScrollableScrollPhysics(), itemCount: items.length, // item 的个数 separatorBuilder: (BuildContext context, int index) => Divider(height: 1.0), // 添加分割线 itemBuilder: (BuildContext context, int index) { SortCondition goodsSortCondition = items[index]; return InkWell( onTap: () { for (var value in items) { value.isSelected = false; } goodsSortCondition.isSelected = true; itemOnTap(goodsSortCondition); }, child: Container( height: 50, width: double.infinity, alignment: Alignment.center, child: Text( goodsSortCondition.name, textScaleFactor: 1.0, style: TextStyle( color: goodsSortCondition.isSelected ? const Color(0xFF0368FF) : Constants.BlackTextColor, ), )), ); }, ); } }