flutter - 如何在颤动中垂直和水平地居中 CircularProgressIndicator
问题描述
现在我在渲染之前使用容器来占位图像。但现在我面临一个问题,使 CircularProgressIndicator 垂直和水平居中。这就是我现在正在做的事情:
Widget loadingWidget(){
return Container(
height: 400.0,
width: 120.0,
child: Center(
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 50.0, maxWidth: 50.0
),
child:CircularProgressIndicator()
)
),
);
}
在一个固定大小的容器中,我放置了一个 CircularProgressIndicator,现在 CircularProgressIndicator 垂直居中,但横向不是居中。我从互联网上搜索,发现所有方法都非常复杂。有什么简单的方法可以做到这一点,对不起,我是一个关于颤振的新手。我试过这种方式按照答案:
Widget loadingWidget(){
return Container(
height: 400.0,
width: 120.0,
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children:<Widget> [
SizedBox(
child: CircularProgressIndicator(),
height: 50.0,
width: 50.0,
)
],
)
),
);
}
但是左上角的CircularProgressIndicator,为什么没有在容器的中心?这是我的组件的完整代码:
import 'package:cruise/src/common/article_action.dart';
import 'package:cruise/src/common/helpers.dart';
import 'package:cruise/src/common/net/rest/http_result.dart';
import 'package:cruise/src/common/repo.dart';
import 'package:cruise/src/common/utils/common_utils.dart';
import 'package:cruise/src/models/Channel.dart';
import 'package:cruise/src/models/Item.dart';
import 'package:cruise/src/models/api/fav_status.dart';
import 'package:cruise/src/models/api/upvote_status.dart';
import 'package:cruise/src/page/channel/channelpg_component/page.dart';
import 'package:cruise/src/page/home/components/articledetail_component/action.dart';
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html/style.dart';
import 'package:flutter_icons/flutter_icons.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:html/parser.dart' as htmlparser;
import 'package:html/dom.dart' as dom;
import 'state.dart';
Widget buildView(ArticleDetailState state, Dispatch dispatch, ViewService viewService) {
Item item = state.article;
BuildContext context = viewService.context;
Offset? _initialSwipeOffset;
Offset? _finalSwipeOffset;
void _onHorizontalDragStart(DragStartDetails details) {
_initialSwipeOffset = details.globalPosition;
}
void _onHorizontalDragUpdate(DragUpdateDetails details) {
_finalSwipeOffset = details.globalPosition;
}
void _onHorizontalDragEnd(DragEndDetails details) {
if (_initialSwipeOffset != null) {
final offsetDifference = _initialSwipeOffset!.dx - _finalSwipeOffset!.dx;
if (offsetDifference < 0) {
Navigator.pop(context);
}
}
}
void touchUpvote(String action, UpvoteStatus upvoteStatus) async {
HttpResult result = (await ArticleAction.upvote(articleId: item.id.toString(), action: action))!;
if (result.result == Result.error) {
Fluttertoast.showToast(
msg: "点赞失败",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
} else {
if (upvoteStatus.statusCode == "upvote") {
dispatch(ArticleDetailActionCreator.onVote(UpvoteStatus.UPVOTE));
}
if (upvoteStatus.statusCode == "unupvote" && item.upvoteCount > 0) {
dispatch(ArticleDetailActionCreator.onVote(UpvoteStatus.UNUPVOTE));
}
Fluttertoast.showToast(
msg: upvoteStatus.statusCode == "upvote" ? "点赞成功" : "取消点赞成功",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
}
}
void touchFav(String action, FavStatus favStatus) async {
HttpResult result = (await ArticleAction.fav(articleId: item.id.toString(), action: action))!;
if (result.result == Result.error) {
Fluttertoast.showToast(
msg: favStatus.statusCode == "fav" ? "添加收藏失败" : "取消收藏失败",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
} else {
if (favStatus.statusCode == "fav") {
dispatch(ArticleDetailActionCreator.onFav(FavStatus.FAV));
}
if (favStatus.statusCode == "unfav" && item.favCount > 0) {
dispatch(ArticleDetailActionCreator.onFav(FavStatus.UNFAV));
}
Fluttertoast.showToast(
msg: favStatus.statusCode == "fav" ? "添加收藏成功" : "取消收藏成功",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
}
}
void navToChannelDetail() async {
Channel channel = (await Repo.fetchChannelItem(int.parse(item.subSourceId)))!;
var data = {'name': "originalstories", "channel": channel};
Widget page = ChannelpgPage().buildPage(data);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => page),
);
}
/// 是否是编辑选择频道链接显示不同的颜色
TextStyle getDomainStyle(Item article){
if(article.editorPick == 1) {
return new TextStyle(
color: Color(0xFFFFA826),
fontSize: 15
);
}else{
return new TextStyle(
color: Color(0xFF0A0A0A),
fontSize: 15
);
}
}
ImageSourceMatcher base64UriMatcher() => (attributes, element) =>
attributes["src"] != null &&
attributes["src"]!.startsWith("data:image") &&
attributes["src"]!.contains("base64,");
Widget loadingWidget(){
return Container(
height: 400.0,
width: 120.0,
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children:<Widget> [
SizedBox(
child: CircularProgressIndicator(),
height: 50.0,
width: 50.0,
)
],
)
),
);
}
final Map<ImageSourceMatcher, ImageRender> defaultImageRenders = {
base64UriMatcher(): base64ImageRender(),
assetUriMatcher(): assetImageRender(),
networkSourceMatcher(extension: "svg"): svgNetworkImageRender(),
networkSourceMatcher(): networkImageRender(
height: 400,
loadingWidget: loadingWidget
),
};
SingleChildScrollView buildListView(Item item, BuildContext context) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
InkWell(
onTap: () => CommonUtils.launchUrl(item.link),
child: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(
child: Text(
item.title,
style: Theme.of(context).textTheme.headline5!.copyWith(
fontWeight: FontWeight.w600,
),
),
),
),
),
if (item.domain != "")
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: InkWell(
onTap: () async {
navToChannelDetail();
},
child: Text(
item.domain,
style: getDomainStyle(item),
)),
),
InkWell(
onTap: () {},
child: RichText(
text: TextSpan(
children: <TextSpan>[
TextSpan(
text: item.author,
style: Theme.of(context).textTheme.caption,
),
TextSpan(
text: " ${String.fromCharCode(8226)} ",
style: Theme.of(context).textTheme.caption,
),
TextSpan(
text: item.ago,
style: Theme.of(context).textTheme.caption,
),
],
),
),
),
if (item.content != "")
Html(
data: item.content,
style: {
"body": Style(
fontSize: FontSize(19.0),
),
},
customImageRenders: defaultImageRenders,
onLinkTap: (String? url, RenderContext context, Map<String, String> attributes, dom.Element? element){
CommonUtils.launchUrl(url);
}),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Row(
children: [
if (item.isFav == 1)
IconButton(
icon: Icon(Icons.bookmark, color: Theme.of(context).primaryColor),
onPressed: () => touchFav("unfav", FavStatus.UNFAV),
),
if (item.isFav != 1)
IconButton(
icon: Icon(Icons.bookmark),
onPressed: () => touchFav("fav", FavStatus.FAV),
),
Padding(
padding: const EdgeInsets.only(left: 0.0),
child: Text(
"${item.favCount}",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.caption!.copyWith(
color: Theme.of(context).primaryColor,
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(bottom: 0.0),
child: Row(
children: [
if (item.isUpvote == 1)
IconButton(
icon: Icon(Icons.thumb_up, color: Theme.of(context).primaryColor),
onPressed: () => touchUpvote("unupvote", UpvoteStatus.UNUPVOTE),
),
if (item.isUpvote != 1)
IconButton(
icon: Icon(Icons.thumb_up),
onPressed: () => touchUpvote("upvote", UpvoteStatus.UPVOTE),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
"${item.upvoteCount}",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.caption!.copyWith(
color: Theme.of(context).primaryColor,
),
),
),
],
),
),
],
),
IconButton(
icon: Icon(
Feather.share_2,
),
onPressed: () => handleShare(id: item.id, title: item.title, postUrl: item.link),
),
],
),
],
));
}
return GestureDetector(
onHorizontalDragStart: _onHorizontalDragStart,
onHorizontalDragUpdate: _onHorizontalDragUpdate,
onHorizontalDragEnd: _onHorizontalDragEnd,
child: Container(
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height * 0.9,
),
color: Theme.of(context).scaffoldBackgroundColor,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: buildListView(item, context),
),
));
}
我正在使用flutter html来渲染html文本,在渲染之前我想要一个组件来代替图像位置,这个问题可能会解释更多细节。
解决方案
CircularProgressIndicator位于左上角,因为Container在调用时默认设置在此处,因此CircularProgressIndicator位于Container的中心,现在位于左上角。
所以你需要做的只是用Center() 小部件包装包含CircularProgressIndicator的容器
推荐阅读
- python - 如何每次创建一个唯一的字母数字 id 并确保它不存在于我使用 python 的现有列表中?
- android - SharedElementTransition 可以交互吗?
- c# - 如何使用 Appium 自动化在 android 模拟器中单击应用程序菜单按钮的事件?
- solr - 精确表达或单词 solr 匹配
- javascript - 如何使用 Vue 指令防止链接或按钮中的点击事件
- oracle - Oracle EBS 12.2.4 与 ADF 的集成
- django - 在 django 中获取 m2m 字段(通过模型)列表
- javascript - Redux 形式,VALUES 来自哪里?
- react-native - React Native - 似乎没有调用函数
- python - 从列表中检测异常值