Flipter中RelativeLayout的等价物
有没有类似于RelativeLayout在Android上做什么的方法?Flipter中RelativeLayout的等价物
特别是我在寻找类似的东西centerInParent,layout_below :, layout_above:和alignParentLeft
有关的RelativeLayout更多参考:https://developer.android.com/reference/android/widget/RelativeLayout.LayoutParams.html
编辑:这里是一个布局的依托一个例子RelativeLayout
所以在上面的图片中,在顶部,“豆腐的歌曲”文本在相对布局内对齐为centerInParent。而其他2个是alignParentLeft和alignParentRight
在每个单元格上,火图标所在的位置,底部的喜欢数量都围绕火焰图标的中心对齐。此外,每个单元格的顶部和底部标题分别与图像化身的右侧和顶部以及底部对齐。
颤动布局通常使用Column
,Row
和Stack
小部件树来构建。这些小部件采用构造函数参数来指定子项相对于父项的布局规则,还可以通过将子项包装在Expanded
,Flexible
,Positioned
,Align
或Center
小部件中来影响各个子项的布局。
也可以使用CustomMultiChildLayout
构建复杂的布局。这是Scaffold
是如何在内部实现的,如何在应用程序中使用它的示例出现在Shrine demo中。您还可以使用LayoutBuilder
或CustomPaint
,或者沿着sector example所示向下一层并延伸RenderObject
。以这种方式手动完成布局会更有效,并且会在边角情况下产生更多潜在的错误,所以如果可以的话,我会尝试使用高级布局基元。
为了回答您的具体问题:
- 使用
leading
和trailing
参数AppBar
来定位你的应用程序栏元素。如果您想要使用,请使用MainAxisAlignment.spaceBetween
的mainAxisAlignment
。 - 使用
Row
与crossAxisAlignment
的CrossAxisAlignment.center
将火图标和编号放置在下面。 - 使用
Column
与mainAxisAlignment
的MainAxisAlignment.spaceBetween
来定位您的顶部和底部标题。 (您应该考虑使用ListTile
奠定了名单的瓷砖,但如果你这样做,你将失去控制权的精确定位。)
下面的代码片段实现您所提供的设计。在这个例子中,我使用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
,但你也可以使用一个固定SliverAppBar
拥有的0.0 elevation
一个CustomScrollView
。这会使内容在应用栏后滚动时可见。要使它与PageView
很好地搭配很困难,因为它期望有一个固定尺寸的区域。
感谢Collin的回复!我发布了一个截图的例子,我使用RelativeLayout – user3217522
非常感谢你这么详细的答案! – user3217522
我希望我可以多次投票。 –