相当于Flutter中的RelativeLayout
有没有办法实现类似于 Android RelativeLayout
上的功能?
特别是我在寻找类似的东西来centerInParent,layout_below:<layout_id>
,layout_above:<layout_id>
,和alignParentLeft
有关RelativeLayout的更多参考:https ://developer.android.com/reference/android/widget/RelativeLayout.LayoutParams.html
编辑:这是一个依赖于布局的示例 RelativeLayout
屏幕截图
因此,在上图中的顶部,“豆腐的歌曲”文本与centerInParent
内对齐RelativeLayout
。而其他2个是alignParentLeft
和alignParentRight
在每个带有火图标的单元格上,其底部的点赞次数围绕着火图标的中心对齐。同样,每个单元格的顶部和底部标题分别与图像头像的右侧和顶部和底部对齐。
回答:
Flutter 正在使用的树通常建立
Column
,
Row
and
Stack
widgets.
这些小部件采取了怎样指定规则构造函数参数
的儿童相对于父摆出来,你也可以影响
通过包裹它们成为个体儿童的布局
Expanded
,
Flexible
,
Positioned
,
Align
, or
Center
widgets.
It is also possible to build complex layouts using
CustomMultiChildLayout
. This is how
Scaffold
is
implemented internally, and an example of how to use it in an app appears in
the Shrine
demo.
You can also use
LayoutBuilder
or
CustomPaint
, or go down a layer and extend
RenderObject
as shown in the sector
example.
Doing your layouts manually like this is more work and creates more potential
for errors in corner cases, so I would try to get by with the high-level
layout primitives if you can.
To answer your specific questions:
- 使用
leading
和trailing
参数来AppBar
放置应用栏元素。如果要改用a Row,请使用mainAxisAlignment
ofMainAxisAlignment.spaceBetween
. - Use a
Row
with acrossAxisAlignment
ofCrossAxisAlignment.center
to position the fire icon and number underneath. - Use a
Column
with amainAxisAlignment
ofMainAxisAlignment.spaceBetween
to position your top and bottom title. (You should consider usingListTile
to lay out the list tiles, but you’ll lose control over the exact positioning if you do this.)
这是实现您提供的设计的代码段。在此示例中,我使用IntrinsicHeight来确定歌曲图块的高度,但是您可以通过将其硬编码为固定高度来提高性能。
import 'package:flutter/material.dart';void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
brightness: Brightness.dark,
primaryColorBrightness: Brightness.dark,
),
home: new HomeScreen(),
debugShowCheckedModeBanner: false,
);
}
}
class Song extends StatelessWidget {
const Song({ this.title, this.author, this.likes });
final String title;
final String author;
final int likes;
@override
Widget build(BuildContext context) {
TextTheme textTheme = Theme
.of(context)
.textTheme;
return new Container(
margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 10.0),
decoration: new BoxDecoration(
color: Colors.grey.shade200.withOpacity(0.3),
borderRadius: new BorderRadius.circular(5.0),
),
child: new IntrinsicHeight(
child: new Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new Container(
margin: const EdgeInsets.only(top: 4.0, bottom: 4.0, right: 10.0),
child: new CircleAvatar(
backgroundImage: new NetworkImage(
'http://thecatapi.com/api/images/get?format=src'
'&size=small&type=jpg#${title.hashCode}'
),
radius: 20.0,
),
),
new Expanded(
child: new Container(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Text(title, style: textTheme.subhead),
new Text(author, style: textTheme.caption),
],
),
),
),
new Container(
margin: new EdgeInsets.symmetric(horizontal: 5.0),
child: new InkWell(
child: new Icon(Icons.play_arrow, size: 40.0),
onTap: () {
// TODO(implement)
},
),
),
new Container(
margin: new EdgeInsets.symmetric(horizontal: 5.0),
child: new InkWell(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Icon(Icons.favorite, size: 25.0),
new Text('${likes ?? ''}'),
],
),
onTap: () {
// TODO(implement)
},
),
),
],
),
),
);
}
}
class Feed extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new ListView(
children: [
new Song(title: 'Trapadelic lobo', author: 'lillobobeats', likes: 4),
new Song(title: 'Different', author: 'younglowkey', likes: 23),
new Song(title: 'Future', author: 'younglowkey', likes: 2),
new Song(title: 'ASAP', author: 'tha_producer808', likes: 13),
new Song(title: '????????????', author: 'TraphousePeyton'),
new Song(title: 'Something sweet...', author: '6ryan'),
new Song(title: 'Sharpie', author: 'Fergie_6'),
],
);
}
}
class CustomTabBar extends AnimatedWidget implements PreferredSizeWidget {
CustomTabBar({ this.pageController, this.pageNames })
: super(listenable: pageController);
final PageController pageController;
final List<String> pageNames;
@override
final Size preferredSize = new Size(0.0, 40.0);
@override
Widget build(BuildContext context) {
TextTheme textTheme = Theme
.of(context)
.textTheme;
return new Container(
height: 40.0,
margin: const EdgeInsets.all(10.0),
padding: const EdgeInsets.symmetric(horizontal: 20.0),
decoration: new BoxDecoration(
color: Colors.grey.shade800.withOpacity(0.5),
borderRadius: new BorderRadius.circular(20.0),
),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: new List.generate(pageNames.length, (int index) {
return new InkWell(
child: new Text(
pageNames[index],
style: textTheme.subhead.copyWith(
color: Colors.white.withOpacity(
index == pageController.page ? 1.0 : 0.2,
),
)
),
onTap: () {
pageController.animateToPage(
index,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
}
);
})
.toList(),
),
);
}
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => new _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
PageController _pageController = new PageController(initialPage: 2);
@override
build(BuildContext context) {
final Map<String, Widget> pages = <String, Widget>{
'My Music': new Center(
child: new Text('My Music not implemented'),
),
'Shared': new Center(
child: new Text('Shared not implemented'),
),
'Feed': new Feed(),
};
TextTheme textTheme = Theme
.of(context)
.textTheme;
return new Stack(
children: [
new Container(
decoration: new BoxDecoration(
gradient: new LinearGradient(
begin: FractionalOffset.topCenter,
end: FractionalOffset.bottomCenter,
colors: [
const Color.fromARGB(255, 253, 72, 72),
const Color.fromARGB(255, 87, 97, 249),
],
stops: [0.0, 1.0],
)
),
child: new Align(
alignment: FractionalOffset.bottomCenter,
child: new Container(
padding: const EdgeInsets.all(10.0),
child: new Text(
'T I Z E',
style: textTheme.headline.copyWith(
color: Colors.grey.shade800.withOpacity(0.8),
fontWeight: FontWeight.bold,
),
),
)
)
),
new Scaffold(
backgroundColor: const Color(0x00000000),
appBar: new AppBar(
backgroundColor: const Color(0x00000000),
elevation: 0.0,
leading: new Center(
child: new ClipOval(
child: new Image.network(
'http://i.imgur.com/TtNPTe0.jpg',
),
),
),
actions: [
new IconButton(
icon: new Icon(Icons.add),
onPressed: () {
// TODO: implement
},
),
],
title: const Text('tofu\'s songs'),
bottom: new CustomTabBar(
pageController: _pageController,
pageNames: pages.keys.toList(),
),
),
body: new PageView(
controller: _pageController,
children: pages.values.toList(),
),
),
],
);
}
}
最后说明一点:在这个例子中,我使用了一个常规的AppBar
,但你也可以使用一个CustomScrollView
具有钉SliverAppBar
有一个elevation
的0.0。这将使内容在滚动到应用程序栏后面时可见。这是棘手得到这个与发挥很好PageView,因为它期待一个固定大小的区域,本身奠定了进去。
以上是 相当于Flutter中的RelativeLayout 的全部内容, 来源链接: utcz.com/qa/400437.html