接入圈子列表数据,增加视频播放页

This commit is contained in:
CYH 2023-06-29 18:11:03 +08:00
parent e065158817
commit f3cf90898e
9 changed files with 946 additions and 405 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -38,12 +38,6 @@ class Call_outLogic extends GetxController {
videoPlayerController?.dispose();
}
@override
void dispose() {
videoPlayerController?.dispose();
super.dispose();
}
@override
void onInit() async {
super.onInit();

View File

@ -5,3 +5,170 @@ class CircleState {
///Initialize variables
}
}
class Lists {
List<Album>? album;
Chat? chat;
String? content;
int? id;
bool? isQueen;
User? user;
Lists(
{this.album, this.chat, this.content, this.id, this.isQueen, this.user});
Lists.fromJson(Map<String, dynamic> json) {
if (json['album'] != null) {
album = <Album>[];
json['album'].forEach((v) {
album!.add(new Album.fromJson(v));
});
}
chat = json['chat'] != null ? new Chat.fromJson(json['chat']) : null;
content = json['content'];
id = json['id'];
isQueen = json['is_queen'];
user = json['user'] != null ? new User.fromJson(json['user']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.album != null) {
data['album'] = this.album!.map((v) => v.toJson()).toList();
}
if (this.chat != null) {
data['chat'] = this.chat!.toJson();
}
data['content'] = this.content;
data['id'] = this.id;
data['is_queen'] = this.isQueen;
if (this.user != null) {
data['user'] = this.user!.toJson();
}
return data;
}
}
class Album {
int? type;
String? url;
Album({this.type, this.url});
Album.fromJson(Map<String, dynamic> json) {
type = json['type'];
url = json['url'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['type'] = this.type;
data['url'] = this.url;
return data;
}
}
class Chat {
String? accountId;
int? count;
List<Users>? users;
Chat({this.accountId, this.count, this.users});
Chat.fromJson(Map<String, dynamic> json) {
accountId = json['account_id'];
count = json['count'];
if (json['users'] != null) {
users = <Users>[];
json['users'].forEach((v) {
users!.add(new Users.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['account_id'] = this.accountId;
data['count'] = this.count;
if (this.users != null) {
data['users'] = this.users!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Users {
String? avatar;
int? id;
String? nickname;
Users({this.avatar, this.id, this.nickname});
Users.fromJson(Map<String, dynamic> json) {
avatar = json['avatar'];
id = json['id'];
nickname = json['nickname'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['avatar'] = this.avatar;
data['id'] = this.id;
data['nickname'] = this.nickname;
return data;
}
}
class User {
String? avatar;
String? city;
int? gender;
int? id;
double? lat;
double? lng;
String? nickname;
int? orientation;
int? role;
int? vip;
User(
{this.avatar,
this.city,
this.gender,
this.id,
this.lat,
this.lng,
this.nickname,
this.orientation,
this.role,
this.vip});
User.fromJson(Map<String, dynamic> json) {
avatar = json['avatar'];
city = json['city'];
gender = json['gender'];
id = json['id'];
lat = json['lat'] ?? 0.0;
lng = json['lng'] ?? 0.0;
nickname = json['nickname'];
orientation = json['orientation'];
role = json['role'];
vip = json['vip'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['avatar'] = this.avatar;
data['city'] = this.city;
data['gender'] = this.gender;
data['id'] = this.id;
data['lat'] = this.lat;
data['lng'] = this.lng;
data['nickname'] = this.nickname;
data['orientation'] = this.orientation;
data['role'] = this.role;
data['vip'] = this.vip;
return data;
}
}

View File

@ -1,19 +1,45 @@
import 'dart:ffi';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:circle_app/app/circle/logic.dart';
import 'package:circle_app/app/circle/state.dart';
import 'package:circle_app/app/circle/widgets/list_logic.dart';
import 'package:circle_app/app/circle/widgets/video_item.dart';
import 'package:circle_app/router/app_routers.dart';
import 'package:circle_app/util/util.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:get/get.dart';
class InfoListView extends StatelessWidget {
// Get.lazyPut(() => ListLogic());
CircleLogic logic;
Circle bean;
int index;
final ScrollController scrollController = ScrollController();
InfoListView(this.index,this.bean,this.logic, {super.key});
InfoListView(this.index, this.bean, this.logic, {super.key});
List<String> genderList = ['', '女,' 'MTF', 'FTM', 'CD', '酷儿'];
List<String> orientationList = [
'异性恋',
'同性恋',
'双性恋',
'泛性恋',
'无性恋',
'智性恋',
'性单恋'
];
List<String> roleList = ['Sado', 'Maso', 'Dom', 'Sub', 'Switch'];
@override
Widget build(BuildContext context) {
Get.lazyPut(() => ListLogic());
final listsLg = Get.find<ListLogic>();
listsLg.loadCallOutListData(bean.id.toString());
TextSpan descSpan;
TextSpan span;
if (bean.intro.length > 60) {
@ -37,7 +63,6 @@ class InfoListView extends StatelessWidget {
);
}
List<JoinUser> urlList = bean.lastJoinUsers;
List<Widget> widgets = [];
int i = 0;
@ -49,11 +74,15 @@ class InfoListView extends StatelessWidget {
i++;
});
return GetBuilder<ListLogic>(
assignId: true,
builder: (listLogic) {
return ClipRRect(
borderRadius: BorderRadius.circular(10.sp),
child: Container(
width: Get.width,
margin: EdgeInsets.only(left: index > 0 ? 4.sp : 0, right: 4.sp),
margin:
EdgeInsets.only(left: index > 0 ? 4.sp : 0, right: 4.sp),
child: Stack(
children: [
ClipRRect(
@ -69,19 +98,27 @@ class InfoListView extends StatelessWidget {
height: Get.height,
width: Get.width,
margin: EdgeInsets.only(top: 72.sp),
child: ListView.builder(
controller: scrollController,
itemCount: 10,
child: RefreshIndicator(
onRefresh: () async {
listLogic.refreshData();
},
child: listLogic.lists.isEmpty
? loaddingWidget(true)
: ListView.builder(
scrollDirection: Axis.vertical,
controller: listLogic.scrollController,
itemCount: listLogic.lists.length + 2,
itemBuilder: (context, index) {
if (index == 0) {
return Container(
padding: EdgeInsets.only(left: 12.sp, right: 12.sp),
padding: EdgeInsets.only(
left: 12.sp, right: 12.sp),
height: 88.sp,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage(
getCircleImage('circle_desc')))),
image: AssetImage(getCircleImage(
'circle_desc')))),
child: Container(
margin: EdgeInsets.only(top: 14.sp),
child: Column(
@ -97,7 +134,8 @@ class InfoListView extends StatelessWidget {
child: RichText(
overflow: TextOverflow.fade,
maxLines: 2,
text: TextSpan(children: <InlineSpan>[
text: TextSpan(
children: <InlineSpan>[
descSpan,
span
])),
@ -112,7 +150,8 @@ class InfoListView extends StatelessWidget {
height: 30.sp,
width: 30.0.sp +
15.sp *
(widgets.length - 1.sp),
(widgets.length -
1.sp),
child: Stack(
children: widgets,
),
@ -142,13 +181,21 @@ class InfoListView extends StatelessWidget {
),
),
);
} else if (index == 1) {
return vipDynamicItem(bean);
} else if (listLogic.lists.length + 1 >
index) {
Lists lists = listLogic.lists[index - 1];
if (lists.isQueen!) {
return vipDynamicItem(lists);
} else {
return normalDynamicItem(bean);
return normalDynamicItem(lists);
}
} else {
return loaddingWidget(
listLogic.callOutMore);
}
}),
),
),
ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.sp),
@ -159,8 +206,8 @@ class InfoListView extends StatelessWidget {
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image:
AssetImage(getCircleImage('top_circle_bg')))),
image: AssetImage(
getCircleImage('top_circle_bg')))),
child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -169,7 +216,7 @@ class InfoListView extends StatelessWidget {
height: 42.sp,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
gradient: LinearGradient(
gradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
@ -191,7 +238,8 @@ class InfoListView extends StatelessWidget {
),
Expanded(
child: Container(
padding: EdgeInsets.only(left: 8.sp, top: 12.sp),
padding:
EdgeInsets.only(left: 8.sp, top: 12.sp),
// alignment: Alignment.,
height: 72.sp,
child: Column(
@ -243,7 +291,10 @@ class InfoListView extends StatelessWidget {
)),
],
)));
},
);
}
void _showTextContentDialog(BuildContext context, String msg) {
showDialog(
context: context,
@ -304,35 +355,39 @@ class InfoListView extends StatelessWidget {
);
}
///
vipDynamicItem(Circle bean) {
vipDynamicItem(Lists bean) {
Text descText = Text(
bean.intro,
bean.content!,
style: TextStyle(color: Colors.white, fontSize: 14.sp),
maxLines: 2,
);
List<JoinUser> urlList = bean.lastJoinUsers;
// List<JoinUser> urlList = bean.lastJoinUsers;
List<Widget> widgets = [];
int index = 0;
urlList.forEach((element) {
bean.chat!.users!.forEach((element) {
widgets.add(Positioned(
left: 12.sp * index,
child: circleWidget(element.avatar, width: 24),
child: circleWidget(element.avatar!, width: 24),
));
index++;
});
if (widgets.isNotEmpty) {
widgets.add(Positioned(
left: 12.sp * urlList.length,
left: 12.sp * bean.chat!.users!.length,
child: Image.asset(
getCircleImage('more'),
width: 24.sp,
)));
}
double widgetHeight = 250.sp + contentHeight(bean.content!);
return Container(
margin: EdgeInsets.only(top: 10.sp),
width: Get.width,
height: 279.sp,
height: widgetHeight,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
@ -374,7 +429,7 @@ class InfoListView extends StatelessWidget {
),
ClipOval(
child: Image.network(
'https://p3-passport.byteimg.com/img/user-avatar/eb429d4dbb3c246f580a6f7894f2b246~100x100.awebp',
bean.user!.avatar!,
width: 40.sp,
height: 40.sp,
fit: BoxFit.fill,
@ -392,7 +447,7 @@ class InfoListView extends StatelessWidget {
Row(
children: [
Text(
'圈子名称',
bean.user!.nickname!,
style: TextStyle(
color: Colors.white,
fontSize: 18.sp,
@ -401,7 +456,9 @@ class InfoListView extends StatelessWidget {
SizedBox(
width: 8.sp,
),
Image.asset(
bean.user!.vip! == 0
? Container()
: Image.asset(
getCircleImage('vip'),
width: 36.sp,
)
@ -427,7 +484,7 @@ class InfoListView extends StatelessWidget {
Color(0xffB5D3FF)
])),
child: Text(
'男.33.DOM.异性恋',
'${genderList[bean.user!.gender!]}.${'33'}.${roleList[bean.user!.role!]}.${orientationList[bean.user!.orientation!]}',
style: TextStyle(
color: Colors.black,
fontSize: 12.sp,
@ -443,6 +500,7 @@ class InfoListView extends StatelessWidget {
),
),
Container(
alignment: Alignment.topLeft,
// margin: EdgeInsets.only(top: 4.sp),
child: descText,
),
@ -490,18 +548,28 @@ class InfoListView extends StatelessWidget {
colors: [Color(0xff261240), Color(0xff122D40)])),
child: Row(
children: [
Container(
widgets.isNotEmpty
? Container(
width: 24 + 12.sp * widgets.length - 12.sp,
height: 24.sp,
child: Stack(children: widgets),
),
)
: Container(),
SizedBox(
width: 4.sp,
),
Expanded(
widgets.isNotEmpty
? Expanded(
child: Text(
'1位圈友已私聊',
style: TextStyle(color: Colors.white, fontSize: 12.sp),
'${bean.chat!.count!}位圈友已私聊',
style: TextStyle(
color: Colors.white, fontSize: 12.sp),
))
: Expanded(
child: Text(
'赶紧成为第一位私聊ta的圈友吧',
style: TextStyle(
color: Colors.white, fontSize: 12.sp),
)),
Image.asset(
getCircleImage('chat'),
@ -519,37 +587,55 @@ class InfoListView extends StatelessWidget {
}
///
normalDynamicItem(Circle bean) {
normalDynamicItem(Lists bean) {
Text descText = Text(
bean.intro,
bean.content!,
style: TextStyle(color: Colors.white, fontSize: 14.sp),
maxLines: 2,
// maxLines: 2,
);
List<String> urlList = [
'https://p3-passport.byteimg.com/img/user-avatar/eb429d4dbb3c246f580a6f7894f2b246~100x100.awebp',
'https://p3-passport.byteimg.com/img/user-avatar/eb429d4dbb3c246f580a6f7894f2b246~100x100.awebp',
'https://p3-passport.byteimg.com/img/user-avatar/eb429d4dbb3c246f580a6f7894f2b246~100x100.awebp'
];
double picHeight = 0.0;
int type = 0;
if (bean.album != null) {
if (bean.album!.isNotEmpty) {
Album info = bean.album!.first!;
type = info.type!;
if (info.type == 1) {
if (bean.album!.length > 3) {
picHeight = 218.sp;
}
} else {
picHeight = 109.sp;
}
}
}
List<Widget> widgets = [];
int index = 0;
urlList.forEach((element) {
bean!.chat!.users!.forEach((element) {
widgets.add(Positioned(
left: 12.sp * index,
child: circleWidget(element, width: 24),
child: GestureDetector(
onTap: () {},
child: circleWidget(element.avatar!, width: 24),
),
));
index++;
});
if (widgets.isNotEmpty) {
widgets.add(Positioned(
left: 12.sp * urlList.length,
left: 12.sp * bean.chat!.users!.length,
child: Image.asset(
getCircleImage('more'),
width: 24.sp,
)));
}
return Container(
margin: EdgeInsets.only(top: 10.sp),
width: Get.width,
height: 279.sp,
height: 130.sp + contentHeight(bean.content!) + picHeight,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
@ -561,11 +647,23 @@ class InfoListView extends StatelessWidget {
Positioned(
right: 2.sp,
top: 2.sp,
child: Image.asset(getCircleImage('location')),
height: 18.sp,
child: Stack(
alignment: Alignment.center,
children: [
Image.asset(
getCircleImage('location'),
height: 20.sp,
),
Text(
bean.user!.city ?? '外星',
style: TextStyle(color: Colors.white, fontSize: 12.sp),
)
],
),
// height: 18.sp,
),
Container(
height: 279.sp,
height: 130.sp + contentHeight(bean.content!) + picHeight,
width: Get.width,
padding: EdgeInsets.only(left: 12.sp, right: 12.sp),
child: Column(
@ -585,7 +683,7 @@ class InfoListView extends StatelessWidget {
),
ClipOval(
child: Image.network(
'https://p3-passport.byteimg.com/img/user-avatar/eb429d4dbb3c246f580a6f7894f2b246~100x100.awebp',
bean.user!.avatar!,
width: 40.sp,
height: 40.sp,
fit: BoxFit.fill,
@ -603,7 +701,7 @@ class InfoListView extends StatelessWidget {
Row(
children: [
Text(
'圈子名称',
bean.user!.nickname! ?? '',
style: TextStyle(
color: Colors.white,
fontSize: 18.sp,
@ -612,7 +710,9 @@ class InfoListView extends StatelessWidget {
SizedBox(
width: 8.sp,
),
Image.asset(
bean.user!.vip! == 0
? Container()
: Image.asset(
getCircleImage('vip'),
width: 36.sp,
)
@ -630,7 +730,7 @@ class InfoListView extends StatelessWidget {
EdgeInsets.only(left: 6.sp, right: 6.sp),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(9.sp),
gradient: LinearGradient(
gradient: const LinearGradient(
begin: Alignment(0.25, 0.5),
end: Alignment(0.75, 0.5),
colors: [
@ -638,7 +738,7 @@ class InfoListView extends StatelessWidget {
Color(0xffB5D3FF)
])),
child: Text(
'男.33.DOM.异性恋',
'${genderList[bean.user!.gender!]}.${'33'}.${roleList[bean.user!.role!]}.${orientationList[bean.user!.orientation!]}',
style: TextStyle(
color: Colors.black,
fontSize: 12.sp,
@ -654,41 +754,58 @@ class InfoListView extends StatelessWidget {
),
),
Container(
alignment: Alignment.topLeft,
// margin: EdgeInsets.only(top: 4.sp),
child: descText,
),
Container(
height: 100.sp,
picHeight > 0
? Container(
height: picHeight,
margin: EdgeInsets.only(top: 5.sp),
child: GridView(
child: GridView.builder(
itemCount: bean.album!.length,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, //widget
crossAxisSpacing: 8.sp,
mainAxisSpacing: 8.sp,
childAspectRatio: 1.0 //1widget
),
children: <Widget>[
ClipRRect(
itemBuilder: (contentxt, currentIndex) {
Album album = bean.album![currentIndex];
if (album.type == 2) {
return ClipRRect(
borderRadius: BorderRadius.circular(6.sp),
child: Image.network(
'https://pic1.zhimg.com/v2-3be05963f5f3753a8cb75b6692154d4a_720w.jpg?source=172ae18b',
child: VideoItemWidget(album.url!));
}
return GestureDetector(
onTap: () {
var imgList = <String>[];
for (var element in bean.album!) {
imgList.add(element.url!);
}
Get.toNamed(AppRoutes.Swiper, arguments: {
'imaglist': imgList,
'index': currentIndex
});
},
child: ClipRRect(
borderRadius: BorderRadius.circular(6.sp),
child: CachedNetworkImage(
imageUrl: album.url!,
placeholder: (context, url) =>
CircularProgressIndicator(
color: Color(0xFF07FAFB),
),
errorWidget: (context, url, error) =>
Icon(Icons.error),
fit: BoxFit.fill,
),
),
ClipRRect(
borderRadius: BorderRadius.circular(6.sp),
child: Image.network(
'https://pic1.zhimg.com/v2-3be05963f5f3753a8cb75b6692154d4a_720w.jpg?source=172ae18b',
fit: BoxFit.fill),
),
ClipRRect(
borderRadius: BorderRadius.circular(6.sp),
child: Image.network(
'https://pic1.zhimg.com/v2-3be05963f5f3753a8cb75b6692154d4a_720w.jpg?source=172ae18b',
fit: BoxFit.fill),
),
]),
),
);
}))
: Container(),
Container(
height: 34.sp,
padding: EdgeInsets.only(left: 5.sp, right: 10.sp),
@ -701,18 +818,28 @@ class InfoListView extends StatelessWidget {
colors: [Color(0xff261240), Color(0xff122D40)])),
child: Row(
children: [
Container(
widgets.isNotEmpty
? Container(
width: 24 + 12.sp * widgets.length - 12.sp,
height: 24.sp,
child: Stack(children: widgets),
),
)
: Container(),
SizedBox(
width: 4.sp,
),
Expanded(
widgets.isNotEmpty
? Expanded(
child: Text(
'1位圈友已私聊',
style: TextStyle(color: Colors.white, fontSize: 12.sp),
'${bean.chat!.count!}位圈友已私聊',
style: TextStyle(
color: Colors.white, fontSize: 12.sp),
))
: Expanded(
child: Text(
'赶紧成为第一位私聊ta的圈友吧',
style: TextStyle(
color: Colors.white, fontSize: 12.sp),
)),
Image.asset(
getCircleImage('chat'),
@ -729,7 +856,6 @@ class InfoListView extends StatelessWidget {
);
}
circleWidget(String url, {double width = 30}) {
return GestureDetector(
child: Stack(
@ -751,7 +877,6 @@ class InfoListView extends StatelessWidget {
));
}
void _showOutCircleDialog(
BuildContext context, CircleLogic controller, Circle bean) {
showDialog(
@ -889,4 +1014,9 @@ class InfoListView extends StatelessWidget {
},
);
}
double contentHeight(String content) {
return calculateTextHeight(
content, 14.sp, FontWeight.w300, Get.width - 64.sp, 100);
}
}

View File

@ -0,0 +1,64 @@
import 'package:circle_app/app/circle/state.dart';
import 'package:circle_app/network/dio_manager.dart';
import 'package:circle_app/util/util.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class ListLogic extends GetxController {
int callOutPage = 1;
bool isLoad = true;
bool callOutMore = true;
var _circleId = '';
List<Lists> lists = [];
final ScrollController scrollController = ScrollController();
loadCallOutListData(String circleId) async {
_circleId = circleId;
var data = await DioManager.instance.get(
url: "/up-service/interest/$circleId/callouts",
params: {"page": callOutPage, "page_size": "20"});
if (data["code"] == 200) {
List dataList = data["data"]["lists"];
if (callOutPage == 1) {
if (lists.isNotEmpty) {
lists.clear();
}
}
if (dataList.isNotEmpty) {
callOutMore = true;
for (var element in dataList) {
lists.add(Lists.fromJson(element));
}
callOutPage++;
} else {
callOutMore = false;
}
update();
} else {
showToast(data["msg"]);
}
}
void refreshData() {
callOutPage = 1;
callOutMore = true;
loadCallOutListData(_circleId);
}
void loadMore() {
loadCallOutListData(_circleId);
}
@override
void onInit() {
// TODO: implement onInit
super.onInit();
scrollController.addListener(() {
if (scrollController.position.pixels == scrollController.position.maxScrollExtent) {
loadMore();
}
});
}
}

View File

@ -0,0 +1,112 @@
import 'package:circle_app/util/util.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:video_player/video_player.dart';
class PlayVideoView extends StatefulWidget {
String url;
PlayVideoView(this.url, {Key? key}) : super(key: key);
@override
State<PlayVideoView> createState() => _PlayVideoViewState();
}
class _PlayVideoViewState extends State<PlayVideoView> {
VideoPlayerController? videoPlayerController;
@override
void initState() {
super.initState();
videoPlayerController = VideoPlayerController.network(widget.url)
..initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
videoPlayerController?.addListener(() async {
// value.position == value.duration
if (videoPlayerController?.value.position ==
videoPlayerController?.value.duration) {
// videoPlayerController?.pause();
await videoPlayerController?.seekTo(Duration.zero);
setState(() {});
}
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
videoPlayerController?.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Stack(
children: [
Container(
width: Get.width,
height: Get.height,
child: GestureDetector(
onTap: () {
if (videoPlayerController!.value.isPlaying) {
videoPlayerController!.pause();
} else {
videoPlayerController!.play();
}
setState(() {});
},
child: Stack(
alignment: Alignment.center,
children: [
AspectRatio(
aspectRatio: videoPlayerController!.value.aspectRatio,
child: VideoPlayer(videoPlayerController!)),
Center(
child: videoPlayerController!.value.isPlaying
? Container()
: Image(
image: AssetImage(getMineImage("icon_play")),
width: 60.sp,
height: 60.sp,
),
),
],
),
),
),
Positioned(
bottom: 0,
child: SafeArea(
child: SizedBox(
width: Get.width,
height: 10.sp,
child: VideoProgressIndicator(videoPlayerController!,
allowScrubbing: true,
colors: const VideoProgressColors(
playedColor: Colors.white,
bufferedColor: Colors.white54,
backgroundColor: Colors.black)),
),
)),
Positioned(
left: 15.sp,
top: Get.statusBarHeight,
child: GestureDetector(
onTap: () {
Get.back();
},
child: Image.asset(
'assets/images/navigator/back.png',
width: 36.sp,
height: 36.sp,
)),
)
],
),
);
}
}

View File

@ -0,0 +1,62 @@
import 'package:circle_app/app/circle/widgets/play_video_view.dart';
import 'package:circle_app/util/util.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:video_player/video_player.dart';
class VideoItemWidget extends StatefulWidget {
String url;
VideoItemWidget(this.url,{Key? key}) : super(key: key);
@override
State<VideoItemWidget> createState() => _VideoItemWidgetState();
}
class _VideoItemWidgetState extends State<VideoItemWidget> {
VideoPlayerController? videoPlayerController;
@override
void initState() {
super.initState();
videoPlayerController = VideoPlayerController.network(
widget.url)
..initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
videoPlayerController?.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Get.to(PlayVideoView(widget.url));
},
child: AspectRatio(
aspectRatio: videoPlayerController!.value.aspectRatio,
child: Stack(
children: [
VideoPlayer(videoPlayerController!),
Center(
child: videoPlayerController!.value.isPlaying
? Container()
: Image(
image: AssetImage(getMineImage("icon_play")),
width: 30.sp,
height: 30.sp,
),
),
],
),
),
);
}
}

View File

@ -2,11 +2,11 @@ import 'dart:ui';
import 'package:circle_app/common/values/values.dart';
import 'package:circle_app/router/app_routers.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:get/get.dart';
import 'package:get/get_state_manager/get_state_manager.dart';
class Util {
@ -59,6 +59,16 @@ showToast(String msg) {
);
}
loaddingWidget(bool isMore) {
return Container(
alignment: Alignment.center,
child: isMore ? const CircularProgressIndicator(color: Color(0xFF07FAFB),) : Container(
margin:EdgeInsets.only(top: 4.sp,bottom: 4.sp),
child: Text('--到底了--',style: TextStyle(color: Colors.white,fontSize: 13.sp),
),),
);
}
///value: fontSize : fontWeightmaxWidthmaxLines
double calculateTextHeight(String value, fontSize, FontWeight fontWeight,
double maxWidth, int maxLines) {

View File

@ -76,6 +76,8 @@ dependencies:
package_info_plus: ^1.4.3+1
#视频播放器
video_player: ^2.6.1
#图片缓存
cached_network_image: ^3.2.3