first commit

This commit is contained in:
编码猿
2024-09-27 01:32:49 +08:00
commit 28ebe05a64
7399 changed files with 1174529 additions and 0 deletions

View File

@@ -0,0 +1 @@
59007402-c266-46da-982c-7256cce36767

View File

@@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:peach/config/_.dart';
import 'package:peach/utils/_.dart';
/// cell 组件
class CellWidget extends StatelessWidget {
final Widget leftIcon;
final Widget leftText;
final Widget rightIcon;
final Widget rightText;
final Function onTap;
final double padding;
CellWidget({
this.leftIcon = const Text(""),
this.leftText,
this.rightIcon = const Icon(Icons.arrow_forward_ios,color: ColorConfig.NoActiveColor,size: 15,),
this.rightText = const Text(""),
this.onTap,
this.padding = 15
});
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.centerLeft,
color: ColorConfig.WhiteBackColor,
child: InkWell(
onTap: () {
onTap();
},
child: Container(
padding: EdgeInsets.only(left: Screen.setFontSize(padding),right: Screen.setFontSize(padding)),
height: Screen.setHeight(48),
child: Row(
children: [
Expanded(
child: Container(
child: Row(
children: [
leftIcon,
SizedBox(width: Screen.setWidth(10),),
leftText
],
),
),
),
rightText,
SizedBox(width: Screen.setWidth(10),),
rightIcon
],
),
),
),
);
}
}

View File

@@ -0,0 +1,28 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/config/Colors.dart';
import 'package:peach/config/Index.dart';
import 'package:peach/utils/_.dart';
/*
* 圆形背景的icon
*/
class CircleTransparentIcon extends StatelessWidget {
final Widget icon;
const CircleTransparentIcon({this.icon});
@override
Widget build(BuildContext context) {
return Opacity(
opacity: 0.5,
child: CircleAvatar(
backgroundColor: ColorConfig.BlackBackColor,
child: Align(
alignment: Alignment.center,
child: this.icon,
),
),
);
}
}

View File

@@ -0,0 +1,59 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/entity/CommenListEntity.dart';
import 'package:peach/utils/_.dart';
import 'package:peach/entity/_.dart';
import '_.dart';
/*
* 评论样式
*/
class CommentList extends StatelessWidget {
final List<CommenListEntity> comment;
final Function reply;
const CommentList({this.comment, this.reply});
@override
Widget build(BuildContext context) {
return Column(
children: [
...comment.asMap().keys.map((e) {
return view(comment[e]);
}).toList(),
],
);
}
Widget view(CommenListEntity data) {
if (data.child.length <= 0) {
return CommentWidget(
comment: data,
reply: () {
reply(data.userNickname, data.commentId);
});
} else {
return Column(
children: [
CommentWidget(
comment: data,
reply: () {
reply(data.userNickname, data.commentId);
}),
...data.child.asMap().keys.map((e) {
return Container(
margin: EdgeInsets.only(left: Screen.setWidth(40)),
child: CommentWidget(
child: data.child[e],
userNickname: "@${data.child[e].commentToUsername } ",
reply: () {
reply(data.child[e].userNickname, data.commentId);
}),
);
}).toList()
],
);
}
}
}

View File

@@ -0,0 +1,120 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:peach/config/_.dart';
import 'package:peach/entity/CommenListEntity.dart';
import 'package:peach/entity/_.dart';
import 'package:peach/utils/Screen.dart';
import 'package:peach/widget/Panel.dart';
/*
* 评论样式
*/
class CommentWidget extends StatelessWidget {
final Function reply;
final CommenListEntity comment;
final String userNickname;
final Child child;
CommentWidget({this.reply, this.comment, this.child, this.userNickname = ""});
var data;
@override
Widget build(BuildContext context) {
data = comment != null ? comment : child;
return Panel(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () {
Modular.to.pushNamed("/personal/${comment.userId}");
},
child: Container(
height: Screen.setWidth(35),
width: Screen.setWidth(35),
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(data.userHeadImg),
fit: BoxFit.fill,
),
),
),
),
Expanded(
flex: 1,
child: Container(
margin: EdgeInsets.only(left: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
data.userNickname,
style: TextStyle(fontSize: 14),
),
Container(
margin: EdgeInsets.only(top: 10),
child: Text.rich(
TextSpan(
text: "${userNickname}",
style: TextStyle(
fontSize: 13,
color: ColorConfig.ThemeColor,
),
recognizer: TapGestureRecognizer()
..onTap = () {
Modular.to.pushNamed("/personal/${data.userId}");
},
children: [
TextSpan(
text: data.commentContent,
style: TextStyle(
color: ColorConfig.TextColor,
),
),
],
),
),
),
Container(
margin: EdgeInsets.only(top: 10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Container(
margin: EdgeInsets.only(right: 10),
child: Text(
data.commentTime,
style: TextStyle(
color: ColorConfig.TextColor, fontSize: 13),
),
),
GestureDetector(
child: Text(
"回复",
style: TextStyle(
fontSize: 14,
color: ColorConfig.ThemeColor,
),
),
onTap: () {
reply();
},
),
],
),
)
],
),
),
),
],
),
);
}
}

View File

@@ -0,0 +1,56 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/config/Colors.dart';
import 'package:peach/config/Index.dart';
import 'package:peach/utils/_.dart';
/*
* 接受头部和内容,当页面向上滑动时内容部分到达顶部会定位
* 并且当到达顶部是会触发回调函数
*/
class ContentPositioningLayout extends StatelessWidget {
final Widget title;
final Widget child;
final double titleHeight;
final double scrollHeight;
const ContentPositioningLayout(
{this.title, this.child, this.titleHeight = 45, this.scrollHeight = 0});
static Color color = Colors.transparent;
@override
Widget build(BuildContext context) {
ScrollController mController = new ScrollController();
mController.addListener(() {
if (scrollHeight == 0) {
return;
}
if ((scrollHeight.truncate() - mController.offset.truncate()) <= 3) {
color = ColorConfig.WhiteBackColor;
} else {
color = Colors.transparent;
}
});
return Stack(
children: <Widget>[
Positioned(
height: Screen.height(context),
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
controller: mController,
child: this.child,
),
),
Positioned(
height: Screen.setHeight(this.titleHeight) + Config.top,
child: Container(
padding: EdgeInsets.only(top: Config.top),
decoration: BoxDecoration(color: color),
child: this.title,
),
),
],
);
}
}

View File

@@ -0,0 +1,39 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/config/Colors.dart';
import 'package:peach/utils/_.dart';
/*
* 数据为空时默认展示
*/
class Empty extends StatelessWidget {
final double height;
final Widget child;
final bool isShow;
Empty({this.height = 100, this.child = null, this.isShow = false});
@override
Widget build(BuildContext context) {
return Container(
width: Screen.width(context),
height: height,
child: isShow
? Container(
padding: EdgeInsets.only(top: 100),
alignment: Alignment.center,
child: Column(
children: [
Icon(
Icons.drafts,
size: 52,
color: ColorConfig.TextColor,
),
Text("暂无数据")
],
),
)
: this.child,
);
}
}

View File

@@ -0,0 +1,27 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/config/Colors.dart';
import 'package:peach/utils/_.dart';
/*
* 数据为空时默认展示 text
*/
class EmptyText extends StatelessWidget {
final double height;
final String text;
EmptyText({
this.height = 100,
this.text = "暂无数据",
});
@override
Widget build(BuildContext context) {
return Container(
width: Screen.width(context),
height: height,
alignment: Alignment.center,
child: Text(this.text),
);
}
}

View File

@@ -0,0 +1,53 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/config/Colors.dart';
import 'package:peach/utils/_.dart';
/*
* 只做展示作用的 搜索框
*/
class ExhibitionSearch extends StatelessWidget {
final controller = TextEditingController();
final double height;
final Color backgroundColor;
ExhibitionSearch(
{this.height = 28, this.backgroundColor = ColorConfig.WhiteBackColor});
@override
Widget build(BuildContext context) {
return Container(
height: Screen.setHeight(this.height),
child: Container(
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.all(Radius.circular(20.0)),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
verticalDirection: VerticalDirection.up,
children: <Widget>[
SizedBox(
width: 10,
),
Icon(
Icons.search,
color: ColorConfig.TextColor,
size: 18,
),
SizedBox(
width: 5,
),
Expanded(
child: Text(
"搜索动态",
style: TextStyle(color: ColorConfig.TextColor, fontSize: 15),
),
)
],
),
),
);
}
}

View File

@@ -0,0 +1,64 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/config/_.dart';
import 'package:peach/entity/_.dart';
import 'package:peach/utils/_.dart';
/*
* 关注按钮样式
*/
class FollowButton extends StatelessWidget {
final bool isCheck;
final Function onPressed;
const FollowButton({this.isCheck, this.onPressed});
@override
Widget build(BuildContext context) {
return isCheck
? ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith(
(states) {
//设置按下时的背景颜色
if (states.contains(MaterialState.pressed)) {
return ColorConfig.AshPlacement;
}
//默认不使用背景颜色
return ColorConfig.AshPlacement;
},
),
elevation: MaterialStateProperty.all(0),
),
child: Text(
"已关注",
style: TextStyle(fontSize: 15, letterSpacing: 2,color: ColorConfig.TextColor),
),
onPressed: () {
onPressed();
},
)
: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith(
(states) {
//设置按下时的背景颜色
if (states.contains(MaterialState.pressed)) {
return ColorConfig.ThemeOtherColor;
}
//默认不使用背景颜色
return ColorConfig.ThemeColor;
},
),
elevation: MaterialStateProperty.all(0),
),
child: Text(
"关注",
style: TextStyle(fontSize: 15, letterSpacing: 2, color: ColorConfig.WhiteBackColor),
),
onPressed: () {
onPressed();
},
);
}
}

View File

@@ -0,0 +1,162 @@
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:peach/config/Colors.dart';
import 'package:peach/entity/_.dart';
import 'package:peach/utils/_.dart';
/*
* 选择相册或者拍照
*/
class ImagePickerWidget extends StatelessWidget {
final Widget child;
final Function onChange;
const ImagePickerWidget({this.child, this.onChange});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
_showCupertinoActionSheet(context);
},
child: child,
);
}
_showCupertinoActionSheet(BuildContext context) async {
var result = await showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
builder: (context) {
return new Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text("拍照"),
onTap: () async {
Navigator.pop(context);
},
),
Divider(height: 1),
new ListTile(
leading: new Icon(Icons.photo_library),
title: new Text("相册"),
onTap: () async {
Navigator.pop(context);
},
),
Divider(height: 1),
Container(
height: Screen.setHeight(40),
child: Text("取 消", style: TextStyle(color: ColorConfig.ThemeColor,fontSize: Screen.setFontSize(18)),),
alignment: Alignment.center,
)
],
);
},
);
if (result == 'photograph') {
image(ImageSource.camera);
} else if (result == 'album') {
image(ImageSource.gallery);
}
}
Future image(ImageSource type) async {
final pickedFile = await ImagePicker().getImage(source: type);
if (pickedFile != null) {
onChange(ImagePickerEntity(
path: File(pickedFile.path), pickedFile: pickedFile));
}
}
}
// import 'dart:io';
//
// import 'package:flutter/cupertino.dart';
// import 'package:flutter/material.dart';
// import 'package:image_picker/image_picker.dart';
// import 'package:peach/config/Colors.dart';
// import 'package:peach/entity/_.dart';
//
// /*
// * 选择相册或者拍照
// */
// class ImagePickerWidget extends StatelessWidget {
// final Widget child;
// final Function onChange;
//
// const ImagePickerWidget({this.child, this.onChange});
//
// @override
// Widget build(BuildContext context) {
// return GestureDetector(
// onTap: () {
// _showCupertinoActionSheet(context);
// },
// child: child,
// );
// }
//
// _showCupertinoActionSheet(BuildContext context) async {
// var result = await showCupertinoModalPopup(
// context: context,
// builder: (context) {
// return CupertinoActionSheet(
// actions: <Widget>[
// CupertinoActionSheetAction(
// child: Text(
// '拍照',
// style: TextStyle(color: ColorConfig.ThemeColor),
// ),
// onPressed: () {
// Navigator.of(context).pop('photograph');
// },
// isDefaultAction: true,
// ),
// CupertinoActionSheetAction(
// child: Text(
// '相册',
// style: TextStyle(color: ColorConfig.ThemeColor),
// ),
// onPressed: () {
// Navigator.of(context).pop('album');
// },
// isDefaultAction: true,
// ),
// ],
// cancelButton: CupertinoActionSheetAction(
// child: Text(
// '取消',
// style: TextStyle(color: ColorConfig.ThemeColor),
// ),
// onPressed: () {
// Navigator.of(context).pop('cancel');
// },
// ),
// );
// },
// );
//
// if (result == 'photograph') {
// image(ImageSource.camera);
// } else if (result == 'album') {
// image(ImageSource.gallery);
// }
// }
//
// Future image(ImageSource type) async {
// final pickedFile = await ImagePicker().getImage(source: type);
// if (pickedFile != null) {
// onChange(ImagePickerEntity(
// path: File(pickedFile.path), pickedFile: pickedFile));
// }
// }
// }

View File

@@ -0,0 +1 @@
317afd6d-ca10-4a61-878f-aadcb5686fda

View File

@@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
import 'extra_item_container.dart';
class DefaultExtraWidget extends StatefulWidget {
@override
_DefaultExtraWidgetState createState() => _DefaultExtraWidgetState();
}
class _DefaultExtraWidgetState extends State<DefaultExtraWidget> {
@override
Widget build(BuildContext context) {
return ExtraItemContainer(
items: [
createitem(),
createitem(),
createitem(),
createitem(),
createitem(),
createitem(),
createitem(),
createitem(),
createitem(),
],
);
}
ExtraItem createitem() => DefaultExtraItem(
icon: Icon(Icons.add),
text: "添加",
onPressed: () {
print("添加");
},
);
}

View File

@@ -0,0 +1,146 @@
import 'package:flutter/material.dart';
class ExtraItemContainer extends StatefulWidget {
final List<ExtraItem> items;
const ExtraItemContainer({
Key key,
this.items,
}) : super(key: key);
@override
_ExtraItemContainerState createState() => _ExtraItemContainerState();
}
class _ExtraItemContainerState extends State<ExtraItemContainer> {
@override
Widget build(BuildContext context) {
final pages = createPages();
return PageView(
children: pages,
);
}
List<Widget> createPages() {
final items = widget.items;
final hasLastPage = items.length % 8 == 0 ? 0 : 1;
final totalPageCount = items.length ~/ 8 + hasLastPage;
List<Widget> pages = [];
for (var i = 0; i < totalPageCount; i++) {
final page = getPage(i);
pages.add(page);
}
return pages;
}
Widget getPage(int page) {
List<ExtraItem> extras = [];
for (var i = 0; i < widget.items.length; i++) {
if (i < page * 8) continue;
if (i > (page + 1) * 8 - 1) continue;
extras.add(widget.items[i]);
}
List<ExtraItem> itemList1 = [];
List<ExtraItem> itemList2 = [];
for (var i = 0; i < extras.length; i++) {
if (i < 4) {
itemList1.add(extras[i]);
} else {
itemList2.add(extras[i]);
}
}
if (itemList1.length < 4) {
final length = itemList1.length;
for (var i = 0; i < 4 - length; i++) {
itemList1.add(EmptyExtraItem());
}
}
if (itemList2.length < 4) {
final length = itemList2.length;
for (var i = 0; i < 4 - length; i++) {
itemList2.add(EmptyExtraItem());
}
}
return Column(
children: <Widget>[
Expanded(
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
for (final item in itemList1)
Expanded(
child: item.buildItem(),
)
],
),
),
Expanded(
child: Row(
children: <Widget>[
for (final item in itemList2)
Expanded(
child: item.buildItem(),
)
],
),
),
],
);
}
}
abstract class ExtraItem {
ExtraItem();
factory ExtraItem.def({Widget icon, String text, Function onPressed}) {
return DefaultExtraItem(
icon: icon,
text: text,
onPressed: onPressed,
);
}
Widget buildItem();
}
class DefaultExtraItem extends ExtraItem {
final Widget icon;
final String text;
final Function onPressed;
DefaultExtraItem({
this.icon,
this.text,
this.onPressed,
});
Widget buildItem() {
return InkWell(
onTap: onPressed,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
icon,
Container(
height: 10,
),
Text(text),
],
),
),
);
}
}
class EmptyExtraItem extends ExtraItem {
EmptyExtraItem();
@override
Widget buildItem() => Container();
}

View File

@@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
class ImageButton extends StatefulWidget {
final ImageProvider image;
final Function onPressed;
const ImageButton({
Key key,
this.onPressed,
this.image,
}) : super(key: key);
@override
_ImageButtonState createState() => _ImageButtonState();
}
class _ImageButtonState extends State<ImageButton> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: widget.onPressed,
child: Container(
width: 44,
height: 44,
alignment: Alignment.center,
child: Image(
image: widget.image,
width: 35,
height: 35,
),
),
);
}
}

View File

@@ -0,0 +1,350 @@
import 'dart:async';
import 'package:emojis/emoji.dart';
import 'package:flutter/material.dart';
import 'package:peach/config/_.dart';
import 'package:peach/event/_.dart';
import 'dart:ui' as ui;
import 'package:peach/utils/Screen.dart';
typedef void OnSend(String text);
ChatType _initType = ChatType.text;
double _softKeyHeight = 324.0;
class InputWidget extends StatefulWidget {
final TextEditingController controller;
final Widget extraWidget;
final Widget emojiWidget;
final Widget voiceWidget;
final OnSend onSend;
final Function onFocusNode;
final String hintText;
const InputWidget({
Key key,
@required this.controller,
this.extraWidget,
this.emojiWidget,
this.voiceWidget,
this.onSend,
this.onFocusNode,
this.hintText = "回复",
}) : super(key: key);
@override
InputWidgetState createState() =>
InputWidgetState(this.onSend, this.onFocusNode);
}
class InputWidgetState extends State<InputWidget>
with WidgetsBindingObserver, TickerProviderStateMixin {
final Function onSend;
final Function onFocusNode;
String hintText = "回复";
ChatType currentType = _initType;
FocusNode focusNode = FocusNode();
StreamController<String> inputContentStreamController =
StreamController.broadcast();
InputWidgetState(this.onSend, this.onFocusNode);
Stream<String> get inputContentStream => inputContentStreamController.stream;
AnimationController _bottomHeightController;
double maxHeight = 90;
List<Emoji> emList = Emoji.all().take(100).toList();
Color butColor = ColorConfig.TextColor;
@override
void initState() {
super.initState();
onFocusNode(focusNode);
WidgetsBinding.instance.addObserver(this);
focusNode.addListener(onFocus);
widget.controller.addListener(_onInputChange);
_bottomHeightController = AnimationController(
vsync: this,
duration: Duration(
milliseconds: 250,
),
);
Config.eventBus.on<ClasshHntTextEvent>().listen((event) {
if (event.text != "") {
hintText = event.text;
}
});
}
// bool checkShowSendButton(String text) {
// if (currentType == ChatType.voice) {
// return false;
// }
// if (text.trim().isNotEmpty) {
// return true;
// }
// return false;
// }
@override
void didChangeMetrics() {
final mediaQueryData = MediaQueryData.fromWindow(ui.window);
final keyHeight = mediaQueryData?.viewInsets?.bottom;
if (keyHeight != 0) {
_softKeyHeight = keyHeight;
// updateState(ChatType.text);
} else {
// setState(() {});
}
}
void onFocus() {
if (focusNode.hasFocus) {
updateState(ChatType.text);
}
}
void _onInputChange() {
inputContentStreamController.add(widget.controller.text);
if (widget.controller.text.length > 0) {
butColor = ColorConfig.ThemeColor;
} else {
butColor = ColorConfig.TextColor;
}
setState(() {});
}
@override
void dispose() {
_bottomHeightController.dispose();
inputContentStreamController.close();
widget.controller.removeListener(_onInputChange);
focusNode.removeListener(onFocus);
focusNode.dispose();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(maxHeight: 390),
child: Container(
height: maxHeight,
// decoration: BoxDecoration(
// border: Border(
// top: BorderSide(color: ColorConfig.LineColor, width: 1),
// ),
// ),
child: Column(
children: <Widget>[
buildInputButton(),
Container(
margin: EdgeInsets.only(bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildEmojiButton(),
buildRightButton(),
],
),
),
// Divider(),
_buildBottomContainer(child: _buildBottomItems())
],
),
),
);
}
Widget buildRightButton() {
return ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 25,
),
child: IconButton(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
iconSize: 32,
color: butColor,
enableFeedback: true,
padding: EdgeInsets.only(top: 0),
icon: Icon(Icons.send),
onPressed: () {
if (widget.controller.text.length <= 0) return;
this.onSend(widget.controller.text);
widget.controller.text = "";
},
),
);
}
Widget buildEmojiButton() {
return ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 25,
),
child: IconButton(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
iconSize: 32,
color: ColorConfig.TextColor,
padding: EdgeInsets.only(top: 0),
icon: currentType != ChatType.emoji
? Icon(Icons.mood)
: Icon(Icons.keyboard),
onPressed: () {
if (currentType != ChatType.emoji) {
updateState(ChatType.emoji);
} else {
updateState(ChatType.text);
}
},
),
);
}
Widget buildInputButton() {
final inputButton = TextField(
focusNode: focusNode,
controller: widget.controller,
cursorHeight: 20,
decoration: InputDecoration(
isDense: true,
hintText: hintText,
fillColor: Colors.white,
border: OutlineInputBorder(borderSide: BorderSide.none),
),
);
return Container(
height: Screen.setHeight(35),
padding: EdgeInsets.only(top: 15),
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 25,
),
child: inputButton,
),
);
}
void changeBottomHeight(final double height) {
if (height > 0) {
_bottomHeightController.animateTo(1);
} else {
_bottomHeightController.animateBack(0);
}
}
Future<void> updateState(ChatType type) async {
if (type == ChatType.text || type == ChatType.voice) {
_initType = type;
}
if (type == currentType) {
return;
}
this.currentType = type;
ChangeChatTypeNotification(type).dispatch(context);
if (type != ChatType.text) {
hideSoftKey();
setState(() {
maxHeight = 390;
});
} else {
showSoftKey();
setState(() {
maxHeight = 90;
});
}
if (type == ChatType.emoji || type == ChatType.extra) {
// _currentOtherHeight = _softKeyHeight;
changeBottomHeight(1);
} else {
changeBottomHeight(0);
// _currentOtherHeight = 0;
}
setState(() {});
}
void showSoftKey() {
FocusScope.of(context).requestFocus(focusNode);
}
void hideSoftKey() {
focusNode.unfocus();
}
Widget _buildBottomContainer({Widget child}) {
return SizeTransition(
sizeFactor: _bottomHeightController,
child: Container(
child: child,
height: 300,
),
);
}
Widget _buildBottomItems() {
return Container(
decoration: BoxDecoration(
border: Border(top: BorderSide(width: 1, color: ColorConfig.LineColor)),
),
child: MediaQuery.removePadding(
context: context,
removeTop: true,
removeBottom: true,
child: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 7,
),
children: [
...emList.asMap().keys.map(
(e) {
return GestureDetector(
onTap: () {
widget.controller.text += emList[e].toString();
},
child: Container(
alignment: Alignment.center,
child: Text(
"${emList[e]}",
style: TextStyle(
fontSize: 24,
),
),
),
);
},
).toList(),
],
),
),
);
}
}
enum ChatType {
text,
voice,
emoji,
extra,
}
class ChangeChatTypeNotification extends Notification {
final ChatType type;
ChangeChatTypeNotification(this.type);
}

View File

@@ -0,0 +1,18 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/config/Colors.dart';
import 'package:peach/utils/Screen.dart';
/*
* 大部分布局的左右上下宽高都是固定的所以单独抽一个面板组件
*/
class Line extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
height: 8,
width: Screen.width(context),
color: ColorConfig.LineColor,
);
}
}

View File

@@ -0,0 +1,44 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/config/Colors.dart';
import 'package:peach/utils/Screen.dart';
/*
* 加载动画
*/
class Loading extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
height: Screen.height(context),
width: Screen.width(context),
color: ColorConfig.WhiteBackColor,
child: Center(
child: Container(
padding: EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: Colors.black87, borderRadius: BorderRadius.circular(4.0)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
CircularProgressIndicator(),
Container(
padding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 0),
child: Text(
"加载中~",
style: TextStyle(
color: ColorConfig.TextColor,
fontSize: 16.0,
decoration: TextDecoration.none,
),
),
)
],
),
),
),
);
}
}

View File

@@ -0,0 +1,113 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/config/_.dart';
import 'package:peach/utils/_.dart';
class MyInput extends StatefulWidget {
final String hintText;
const MyInput({this.hintText});
@override
_MyInput createState() => _MyInput(hintText: hintText);
}
/*
* 评论输入框
*/
class _MyInput extends State {
FocusNode focusNode = FocusNode();
TextEditingController textFieldcontroller;
ChatType currentType = ChatType.text;
final String hintText;
double height = 70;
_MyInput({this.hintText = "君观之有言否?"}) {
focusNode.addListener(onFocus);
}
@override
Widget build(BuildContext context) {
return Container(
height: Screen.setHeight(height),
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: ColorConfig.LineColor, width: 1),
),
),
child: Column(
children: [
buildInputButton(),
buildEmojiButton(),
],
),
);
}
Widget buildInputButton() {
return Container(
height: Screen.setHeight(35),
padding: EdgeInsets.only(top: 15),
child: TextField(
focusNode: focusNode,
controller: textFieldcontroller,
cursorHeight: 20,
decoration: InputDecoration(
hintText: hintText,
fillColor: Colors.white,
border: OutlineInputBorder(borderSide: BorderSide.none),
),
),
);
}
Widget buildEmojiButton() {
return ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 25,
),
child: IconButton(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
iconSize: 32,
color: ColorConfig.TextColor,
padding: EdgeInsets.only(top: 0),
icon: currentType != ChatType.emoji
? Icon(Icons.mood)
: Icon(Icons.keyboard),
onPressed: () {
if (currentType != ChatType.emoji) {
updateState(ChatType.emoji);
} else {
updateState(ChatType.text);
}
},
),
);
}
onFocus() {
// print("${focusNode.hasFocus}88888");
// height = 200;
}
updateState(ChatType type) {
if (type == ChatType.text) {
height = 70;
FocusScope.of(context).requestFocus(focusNode);
} else {
height = 200;
focusNode.unfocus();
}
print(height);
setState(() {
currentType = type;
});
}
}
enum ChatType {
text,
emoji,
}

View File

@@ -0,0 +1,21 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/config/Colors.dart';
import 'package:peach/utils/Screen.dart';
/*
* 组件加载时的动画
*/
class PageAnimation extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
height: Screen.height(context),
width: Screen.width(context),
child: CupertinoActivityIndicator(
radius: 10,
),
color: ColorConfig.WhiteBackColor,
);
}
}

View File

@@ -0,0 +1,25 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/utils/Screen.dart';
/*
* 大部分布局的左右上下宽高都是固定的所以单独抽一个面板组件
*/
class Panel extends StatelessWidget {
final double top;
final double bottom;
final Widget child;
const Panel({this.child, this.top = 10.0, this.bottom = 10.0});
@override
Widget build(BuildContext context) {
return Container(
width: Screen.width(context),
child: Padding(
padding: EdgeInsets.only(
left: 10, right: 10, top: this.top, bottom: this.bottom),
child: this.child),
);
}
}

View File

@@ -0,0 +1,210 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:peach/config/Colors.dart';
import 'package:peach/utils/_.dart';
import 'package:peach/widget/TextLimitDisplay.dart';
import 'package:peach/widget/_.dart';
/*
* 头像和粉丝内容等
*/
class PersonalpTitle extends StatelessWidget {
final double headImgHeight;
final bool isEditing;
final bool isText;
final Function onExpand;
final double textHeight;
// 是否是本人空间 true 是
final bool isOpenFollow;
// 是否已经关注 true 是
final bool isFollow;
final Function opusFollowUser;
// 头像
final String imgHead;
final String nickname;
final String autograph;
final int fansNums;
final int satisfiedNums;
final int followNums;
final int userId;
PersonalpTitle({
this.headImgHeight = 58,
this.isEditing = false,
this.onExpand,
this.isText = false,
this.textHeight = 20,
this.imgHead = '',
this.nickname = '',
this.autograph = '',
this.fansNums = 0,
this.satisfiedNums = 0,
this.followNums = 0,
this.isOpenFollow = false,
this.isFollow = false,
this.opusFollowUser,
this.userId = 0,
});
GlobalKey txtKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
margin: EdgeInsets.only(right: Screen.setWidth(40)),
child: ClipOval(
child: Image.network(
imgHead,
width: Screen.setWidth(this.headImgHeight),
height: Screen.setWidth(this.headImgHeight),
fit: BoxFit.cover,
),
)),
Expanded(
flex: 1,
child: Column(
children: [
Container(
width: 160,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
Modular.to.pushNamed("/fans/${userId}");
},
child: Column(
children: [
Text(fansNums.toString(),
style: TextStyle(fontSize: 16)),
Text(
"粉丝",
style: TextStyle(
color: ColorConfig.TextColor,
fontSize: 14,
),
)
],
),
),
GestureDetector(
onTap: () {
Modular.to.pushNamed("/follow/${userId}");
},
child: Column(
children: [
Text(followNums.toString(),
style: TextStyle(fontSize: 16)),
Text(
"关注",
style: TextStyle(
color: ColorConfig.TextColor,
fontSize: 14,
),
)
],
),
),
Column(
children: [
Text(satisfiedNums.toString(),
style: TextStyle(fontSize: 16)),
Text(
"获赞",
style: TextStyle(
color: ColorConfig.TextColor,
fontSize: 14,
),
)
],
)
],
),
),
this.isEditing
? Container(
width: Screen.setWidth(240),
margin: EdgeInsets.only(top: Screen.setFontSize(5)),
child: isOpenFollow
? FollowButton(
isCheck: isFollow,
onPressed: () {
opusFollowUser();
})
: ElevatedButton(
style: ButtonStyle(backgroundColor:
MaterialStateProperty.resolveWith(
(states) {
//设置按下时的背景颜色
if (states
.contains(MaterialState.pressed)) {
return ColorConfig.ThemeOtherColor;
}
//默认不使用背景颜色
return ColorConfig.ThemeColor;
})),
child: Text("编辑资料",
style: TextStyle(fontSize: Screen.setFontSize(18))),
onPressed: () {
Navigator.of(context)
.pushNamed("/editMaterials");
},
),
)
: Container()
],
),
),
],
),
GestureDetector(
onTap: () {
var keyContext = txtKey.currentContext;
if (keyContext != null) {
final txtBox = keyContext.findRenderObject() as RenderBox;
print(
'height ${txtBox.size.height} and width ${txtBox.size.width}');
}
},
child: Container(
margin: EdgeInsets.only(top: Screen.setHeight(10)),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
nickname,
style: TextStyle(
color: ColorConfig.ThemeColor,
fontSize: 16,
),
),
),
),
),
Container(
margin: EdgeInsets.only(top: Screen.setHeight(10)),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
autograph,
style: TextStyle(
color: ColorConfig.TextColor,
fontSize: 14,
),
),
),
),
],
);
}
}

View File

@@ -0,0 +1,62 @@
import 'package:flutter/cupertino.dart';
import 'package:peach/config/_.dart';
/*
* 底部弹出操作栏
*/
class RoutineShowDialog {
static itemShowDialog(BuildContext context) {
showCupertinoModalPopup(
context: context,
builder: (BuildContext context) {
return CupertinoActionSheet(
actions: <Widget>[
CupertinoActionSheetAction(
child: Text(
'复制链接',
style: TextStyle(
color: ColorConfig.ThemeColor,
fontSize: 16,
),
),
onPressed: () {},
isDefaultAction: true,
),
CupertinoActionSheetAction(
child: Text(
'分享',
style: TextStyle(
color: ColorConfig.ThemeColor,
fontSize: 16,
),
),
onPressed: () {},
isDefaultAction: true,
),
CupertinoActionSheetAction(
child: Text(
'举报',
style: TextStyle(
color: ColorConfig.ThemeColor,
fontSize: 16,
),
),
onPressed: () {},
isDefaultAction: true,
),
CupertinoActionSheetAction(
child: Text(
'取消',
style: TextStyle(
fontSize: 16,
),
),
onPressed: () {},
isDestructiveAction: true,
),
],
);
},
);
}
}

View File

@@ -0,0 +1,347 @@
import 'dart:math' show max;
import 'dart:ui' show LineMetrics;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
/// 在文本超出指定行数之后,会显示 展开/收起 按钮的文本展示组件
///
/// 用例1: 常规使用
/// TextLimitDisplay(
/// text: '一大段文字...',
/// minLines: 2,
/// textStyle: TextStyle(color: Colors.blue),
/// )
///
/// 用例2特性化使用-比如 一段文字结尾显示的是 编辑,而点击编辑按钮之后要做一些事, 且显示样式不变
/// TextLimitDisplay(
/// text: '一大段文字...',
/// minLines: 2, // 这两个长度也要设置一致
/// maxLines: 2,
/// isAlwaysDisplay: true, // 按钮始终显示
/// textStyle: TextStyle(color: Colors.blue),
/// shrinkText: '编辑', // 这两个文本文字要设置成一样的
/// expandText: '编辑',
/// onShrink: onEdit, // 两个点击事件也要传递同样的事件
/// onExpand: onEdit,
/// )
class TextLimitDisplay extends StatefulWidget {
final String text;
/// 最少展示几行-在收起的状态下展示几行
final int minLines;
/// 最多展示几行-在展开的状态下展示几行,
/// 默认最多支持显示99行要显示更多的行数需要手动传入
final int maxLines;
/// 文字整体样式
final TextStyle textStyle;
/// 收起、展开文字颜色
final Color keyColor;
/// 收起状态下按钮文字
final String shrinkText;
/// 展开状态下的按钮文字
final String expandText;
/// 当点击收起的时候
final Function onShrink;
/// 当点击展开的时候
final Function onExpand;
/// 结尾按钮是否始终处于显示状态
final bool isAlwaysDisplay;
/// 展开按钮的widget会替换文字
final Icon expandIcon;
/// 收起按钮的widget, 会替换文字
final Icon shrinkIcon;
final bool isExpand;
const TextLimitDisplay({
Key key,
this.text = '',
this.minLines,
this.textStyle,
this.maxLines,
this.keyColor = const Color(0xFF5396FD),
this.shrinkText = '展开',
this.expandText = '收起',
this.onShrink,
this.onExpand,
this.isAlwaysDisplay = false,
this.expandIcon,
this.shrinkIcon,
this.isExpand = false,
}) : super(key: key);
@override
_TextLimitDisplayState createState() => _TextLimitDisplayState();
}
class _TextLimitDisplayState extends State<TextLimitDisplay> {
final GlobalKey _key = GlobalKey();
bool _isExpand = false;
bool _isOver = false;
String _shrinkText;
String _expandText;
@override
void initState() {
init();
super.initState();
}
@override
void dispose() {
_key.currentState?.dispose();
super.dispose();
}
@override
void didUpdateWidget(TextLimitDisplay oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.text.compareTo(oldWidget.text) != 0) {
init();
}
}
void init() {
_shrinkText = widget.text;
_expandText = widget.text;
_isExpand = widget.isExpand;
if (widget.minLines != null && widget.minLines > 0) {
initValue();
}
}
String get _activeText => _isExpand ? _expandBtnText : _shrinkBtnText;
String get _showText => _isExpand ? _expandText : _shrinkText;
int get _minLines => _isExpand ? _maxLines : widget.minLines;
int get _maxLines => widget.maxLines ?? 99;
bool _isOverflow(List metrics, int len) => metrics.length > len;
String get _shrinkBtnText => ' ${widget.shrinkText}';
String get _expandBtnText => ' ${widget.expandText}';
TextStyle get _textStyle =>
DefaultTextStyle.of(context).style.merge(widget.textStyle);
Icon _icon(bool isExpand) => isExpand ? widget.shrinkIcon : widget.expandIcon;
void initValue() {
// TODO: 暂时还剩一个问题是这种延时处理的方式无法保证文本组件一定渲染完成了
Future.delayed(Duration(), () {
// 如果没有渲染完成那么这里就会报错无法获取到size
List<LineMetrics> lineMetrics;
try {
lineMetrics = _paintText(widget.text);
} catch (_) {
lineMetrics = List.generate(
max(99, widget.maxLines ?? 99),
(index) => null,
);
}
setState(() {
_isOver = _isOverflow(lineMetrics, widget.minLines);
if (_isOver) {
_shrinkText =
_calcShrinkText(lineMetrics, widget.minLines, _shrinkBtnText);
_expandText = _calcShrinkText(
lineMetrics,
_maxLines,
_expandBtnText,
isExpand: true,
);
}
});
});
}
List<LineMetrics> _paintText(String text, {double maxWidth}) {
final textPainter = TextPainter(
textDirection: TextDirection.ltr,
text: TextSpan(text: text, style: _textStyle),
);
if (maxWidth != null) {
textPainter.layout(minWidth: maxWidth, maxWidth: maxWidth);
} else {
final textWidth = _key.currentContext.size.width;
textPainter.layout(minWidth: textWidth, maxWidth: textWidth);
}
return textPainter.computeLineMetrics();
}
bool _lenEquals(String text, int len) => _paintText(text).length == len;
void _tapRecognizer() {
setState(() => _isExpand = !_isExpand);
if (_isExpand) {
(widget.onShrink ?? () => {})();
} else {
(widget.onExpand ?? () => {})();
}
}
String _getOverflowedText(
String shrinkText, {
String trailingText = '',
int limitLen = 0,
}) {
int textLen = widget.text.length;
int step = 1;
int count = 0;
while (!_lenEquals('$shrinkText$trailingText', limitLen + 1)) {
if (shrinkText.length + step > textLen) {
count++;
if (count > 10) {
// 死循环检测处理
break;
}
if (step < 1) {
break;
} else {
step = step ~/ 2;
}
} else {
shrinkText = widget.text.substring(0, shrinkText.length + step);
step += 4;
}
}
return shrinkText;
}
/// 获取大于指定宽度的_文本
String _getSpeWidthText(double width) {
String result = '_';
while (!_isOverflow(_paintText(result, maxWidth: width), 1)) {
result += '_';
}
return result;
}
String _calcShrinkText(
List<LineMetrics> lineMetrics,
int len,
String trailingBtnText, {
bool isExpand = false,
}) {
// 如果限制的最大行数超过了实际渲染出来的最大行数,说明根据不会出现溢出的情况
if (len > lineMetrics.length) return widget.text;
final String spacerText = _isOverflow(lineMetrics, len) ? '...' : '';
String trailingText;
if (_icon(isExpand) != null) {
trailingText =
'$spacerText${_getSpeWidthText(_icon(isExpand).size ?? IconTheme.of(context).size)}';
} else {
trailingText = '$spacerText$trailingBtnText';
}
// 计算出n行文本大致的字数根据字数从原文本截取相应的字符串
// double nTextLength = min(len, lineMetrics.length) *
// _key.currentContext.size.width /
// _textStyle.fontSize;
// String shrinkText = widget.text.substring(0, nTextLength.toInt());
// 暂时不能从这里计算长度,当文字带有换行的时候会出问题
String shrinkText = '';
// 下面加上结尾字符不一定会换行,因为字体不是等宽字体
// 所以需要先确定溢出才开始倒算
shrinkText = _getOverflowedText(
shrinkText,
trailingText: trailingText,
limitLen: len,
);
// 这个时候这些文字加上结尾附加文字一定是会换行的
// 所以一直判断如果文字换行的行数大于传入的指定行数,那么就从文字末尾减去一个字符
// 再继续判断,直到文本行数等于传入的指定行数为止
// 使用runes计算避免表情在某些位置报错
final shrinkTextRunnes = shrinkText.runes.toList();
int offset = 0;
while (!_lenEquals('$shrinkText$trailingText', len)) {
if (shrinkTextRunnes.length - offset > 0) {
// shrinkText = shrinkText.substring(0, shrinkText.length - 1);
offset++;
shrinkText = String.fromCharCodes(
shrinkTextRunnes.sublist(0, shrinkTextRunnes.length - offset));
} else {
break;
}
}
return '$shrinkText$spacerText';
}
InlineSpan _trailingBtn() {
if (_icon(_isExpand) != null) {
return WidgetSpan(
child: InkWell(
focusColor: Colors.transparent,
highlightColor: Colors.transparent,
hoverColor: Colors.transparent,
splashColor: Colors.transparent,
onTap: _tapRecognizer,
child: _icon(_isExpand),
),
style: _textStyle.copyWith(color: widget.keyColor),
);
}
return TextSpan(
text: _activeText,
style: _textStyle.copyWith(color: widget.keyColor),
recognizer: TapGestureRecognizer()..onTap = _tapRecognizer,
);
}
Widget _handleText() {
return Stack(
children: [
Text.rich(
TextSpan(
text: _showText,
children: [
if (_isOver || widget.isAlwaysDisplay) _trailingBtn(),
],
),
key: _key,
maxLines: _minLines,
softWrap: true,
overflow: TextOverflow.ellipsis,
style: _textStyle,
),
],
);
}
Widget _dispatch() {
if (widget.minLines != null && widget.minLines > 0) {
return _handleText();
}
return Text(
widget.text,
maxLines: widget.minLines,
style: _textStyle,
);
}
@override
Widget build(BuildContext context) {
return _dispatch();
}
}

View File

@@ -0,0 +1,59 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:peach/config/Colors.dart';
import 'package:peach/entity/_.dart';
/*
* 话题展示
*/
class TopicView extends StatelessWidget {
final Function onTap;
final List<Tags> tag;
final bool edit;
const TopicView({this.tag, this.onTap, this.edit = false});
@override
Widget build(BuildContext context) {
return Wrap(
runSpacing: 3,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
...tag.map((e) {
return GestureDetector(
onTap: () {
Modular.to.pushNamed("/indexResultsList/${e.tagsTitle}/${2}");
},
child: Container(
margin: EdgeInsets.only(right: 10),
child: Text(
"#${e.tagsTitle}",
style: TextStyle(
color: ColorConfig.ThemeColor,
),
),
),
);
}).toList(),
edit
? GestureDetector(
onTap: () {
onTap();
},
child: Container(
margin: EdgeInsets.only(right: 10),
child: Text(
"编辑",
style: TextStyle(
color: ColorConfig.ThemeColor,
),
),
),
)
: Container()
],
);
}
}

View File

@@ -0,0 +1 @@
508f6717-b2ff-4096-b80e-91c006bbd44d

View File

@@ -0,0 +1,80 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'TileWidget.dart';
class StaggeredGridViewPage extends StatelessWidget {
const StaggeredGridViewPage.count({
@required this.title,
@required this.crossAxisCount,
@required this.tiles,
this.mainAxisSpacing: 4.0,
this.crossAxisSpacing: 4.0,
}) : _staggeredGridViewMode = _StaggeredGridViewMode.count,
maxCrossAxisExtent = null;
const StaggeredGridViewPage.extent({
@required this.title,
@required this.maxCrossAxisExtent,
@required this.tiles,
this.mainAxisSpacing: 4.0,
this.crossAxisSpacing: 4.0,
}) : _staggeredGridViewMode = _StaggeredGridViewMode.extent,
crossAxisCount = null;
static const EdgeInsetsGeometry padding =
const EdgeInsets.symmetric(horizontal: 4.0);
final String title;
final List<StaggeredTile> tiles;
final int crossAxisCount;
final double mainAxisSpacing;
final double crossAxisSpacing;
final double maxCrossAxisExtent;
final _StaggeredGridViewMode _staggeredGridViewMode;
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Padding(
padding: const EdgeInsets.only(top: 4.0),
child: _buildStaggeredGridView(context)));
}
Widget _buildStaggeredGridView(BuildContext context) {
switch (_staggeredGridViewMode) {
case _StaggeredGridViewMode.count:
return new StaggeredGridView.countBuilder(
crossAxisCount: crossAxisCount,
itemCount: tiles.length,
itemBuilder: _getChild,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
padding: padding,
staggeredTileBuilder: _getStaggeredTile,
);
default:
return new StaggeredGridView.extentBuilder(
maxCrossAxisExtent: maxCrossAxisExtent,
itemCount: tiles.length,
itemBuilder: _getChild,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
padding: padding,
staggeredTileBuilder: _getStaggeredTile,
);
}
}
StaggeredTile _getStaggeredTile(int i) {
return i >= tiles.length ? null : tiles[i];
}
TileWidget _getChild(BuildContext context, int index) {
return new TileWidget(
key: new ObjectKey(index), index: index, backgroundColor: Colors.green);
}
}
enum _StaggeredGridViewMode { count, extent }

View File

@@ -0,0 +1,24 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class TileWidget extends StatelessWidget {
const TileWidget(
{Key key, @required this.index, this.backgroundColor: Colors.green})
: super(key: key);
final int index;
final Color backgroundColor;
@override
Widget build(BuildContext context) {
return new Container(
color: this.backgroundColor,
child: new Center(
child: new CircleAvatar(
backgroundColor: Colors.white,
child: new Text('$index+1'),
)),
);
}
}

View File

@@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'StaggeredGridViewPage.dart';
const List<StaggeredTile> _tiles = const <StaggeredTile>[
const StaggeredTile.count(2, 2),
const StaggeredTile.count(1, 1),
const StaggeredTile.count(1, 2),
const StaggeredTile.count(1, 1),
const StaggeredTile.count(4, 1),
const StaggeredTile.count(4, 2),
const StaggeredTile.count(1, 1),
const StaggeredTile.count(1, 1),
const StaggeredTile.count(1, 1),
const StaggeredTile.count(1, 1),
const StaggeredTile.count(1, 4),
const StaggeredTile.count(1, 3),
const StaggeredTile.count(1, 2),
const StaggeredTile.count(1, 1),
const StaggeredTile.count(1, 1),
const StaggeredTile.count(1, 1),
const StaggeredTile.count(1, 1),
const StaggeredTile.count(1, 1),
const StaggeredTile.count(1, 1),
const StaggeredTile.count(1, 1),
];
class SpannableCountCountPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const StaggeredGridViewPage.count(
title: 'Spannable (Count, Count)', crossAxisCount: 2, tiles: _tiles);
}
}

View File

@@ -0,0 +1,116 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:peach/config/Colors.dart';
import 'package:peach/entity/_.dart';
import 'package:peach/utils/_.dart';
/*
* 作品的数据展示 点赞 评论 浏览
*/
class WorkDataView extends StatelessWidget {
final MainAxisAlignment mainAxisAlignment;
final OpusOpusInfoEntityData infoData;
final bool isUpvote;
final Function onUpvote;
final bool isCollectionOpus;
final Function onOpusCollectionOpus;
const WorkDataView({
this.mainAxisAlignment = MainAxisAlignment.center,
this.infoData,
this.isUpvote = false,
this.onUpvote,
this.isCollectionOpus = false,
this.onOpusCollectionOpus,
});
@override
Widget build(BuildContext context) {
return Align(
child: Row(
children: [
Expanded(
flex: 1,
child: TextButton(
onPressed: () {
onUpvote();
},
child: Row(
mainAxisAlignment: this.mainAxisAlignment,
children: [
Icon(
Icons.thumb_up,
size: 18,
color: isUpvote
? ColorConfig.ThemeColor
: ColorConfig.TextColor,
),
SizedBox(
width: 5,
),
Text(
infoData.opusSatisfied.toString(),
style: TextStyle(
color: ColorConfig.TextColor,
),
)
],
),
),
),
Expanded(
flex: 1,
child: TextButton(
onPressed: () {
onOpusCollectionOpus();
},
child: Row(
mainAxisAlignment: this.mainAxisAlignment,
children: [
Icon(
Icons.favorite,
size: 18,
color: isCollectionOpus
? ColorConfig.ThemeColor
: ColorConfig.TextColor,
),
SizedBox(
width: 5,
),
Text(
infoData.opusCollection.toString(),
style: TextStyle(
color: ColorConfig.TextColor,
),
)
],
),
),
),
Expanded(
flex: 1,
child: Row(
mainAxisAlignment: this.mainAxisAlignment,
children: [
Icon(
Icons.visibility,
size: 18,
color: ColorConfig.TextColor,
),
SizedBox(
width: 5,
),
Text(
infoData.opusSee.toString(),
style: TextStyle(
color: ColorConfig.TextColor,
),
)
],
),
),
],
),
);
}
}

View File

@@ -0,0 +1,20 @@
library widget;
export 'ExhibitionSearch.dart';
export 'Panel.dart';
export 'PersonalpTitle.dart';
export 'Line.dart';
export 'ContentPositioningLayout.dart';
export 'CircleTransparentIcon.dart';
export 'TopicView.dart';
export 'WorkDataView.dart';
export 'CommentWidget.dart';
export 'CommentList.dart';
export 'ImagePickerWidget.dart';
export 'FollowButton.dart';
export 'PageAnimation.dart';
export 'TextLimitDisplay.dart';
export 'MyInput.dart';
export 'RoutineShowDialog.dart';
export 'Loading.dart';
export 'EmptyText.dart';