Flutter中RelativeLayout的等价物

问题描述 投票:59回答:3

有没有办法实现类似于RelativeLayout在Android上的功能?

特别是我正在寻找类似于centerInParentlayout_below:<layout_id>layout_above:<layout_id>alignParentLeft的东西

有关RelativeLayout的更多参考:https://developer.android.com/reference/android/widget/RelativeLayout.LayoutParams.html

编辑:这是一个依赖RelativeLayout的布局示例

Screenshot

所以在上面的图片中,“tofu's Songs”文本在centerInParent中排列为RelativeLayout。而另外2个是alignParentLeftalignParentRight

在火图标所在的每个单元格上,其底部的喜欢数量围绕火焰图标的中心对齐。此外,每个单元格上的顶部和底部标题分别与图像化身的右侧和顶部和底部对齐。

android dart flutter android-relativelayout
3个回答
178
投票

Flutter布局通常使用ColumnRowStack小部件的树构建。这些小部件采用构造函数参数来指定子元素相对于父元素的布局规则,并且还可以通过将它们包装在ExpandedFlexiblePositionedAlignCenter小部件中来影响单个子元素的布局。

也可以使用CustomMultiChildLayout构建复杂的布局。这就是Scaffold在内部实现的方式,并在Shrine demo中显示了如何在应用程序中使用它的示例。你也可以使用LayoutBuilderCustomPaint,或者向下一层并延伸RenderObject,如sector example所示。像这样手动进行布局是更多的工作,并且在极端情况下产生更多错误的可能性,所以如果可以的话,我会尝试使用高级布局基元。

回答您的具体问题:

  • 使用leadingtrailing参数来定位你的app栏元素。如果你想使用AppBar,请使用RowmainAxisAlignment
  • 使用qazxsw poi和qazxsw poi of qazxsw poi来定位火焰图标和数字。
  • 使用MainAxisAlignment.spaceBetweenRowcrossAxisAlignment来定位你的顶部和底部标题。 (您应该考虑使用CrossAxisAlignment.center布置列表切片,但如果您这样做,您将失去对确切定位的控制。)

这是一个实现您提供的设计的代码片段。在这个例子中,我使用Column来确定歌曲块的高度,但是你可以通过将它们硬编码到固定高度来提高性能。

mainAxisAlignment

MainAxisAlignment.spaceBetween

最后的注释:在这个例子中,我使用了常规的ListTile,但你也可以使用带有固定IntrinsicHeightscreenshot,其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(), ), ), ], ); } } 为0.0。当它滚动到您的应用栏后面时,这将使内容可见。让它与AppBar很好地配合是很棘手的,因为它期望一个固定大小的区域可以自己进入。


13
投票

你可以使用CustomScrollView,并可以让它的孩子为SliverAppBarelevation

示例#1(在PageView中使用Stack

Positioned

示例#2(在Align中使用Positioned

Stack

截图:

Stack( children: <Widget>[ Positioned(left: 0.0, child: Text("Top\nleft")), Positioned(bottom: 0.0, child: Text("Bottom\nleft")), Positioned(top: 0.0, right: 0.0, child: Text("Top\nright")), Positioned(bottom: 0.0, right: 0.0, child: Text("Bottom\nright")), Positioned(bottom: 0.0, right: 0.0, child: Text("Bottom\nright")), Positioned(left: width / 2, top: height / 2, child: Text("Center")), Positioned(top: height / 2, child: Text("Center\nleft")), Positioned(top: height / 2, right: 0.0, child: Text("Center\nright")), Positioned(left: width / 2, child: Text("Center\ntop")), Positioned(left: width / 2, bottom: 0.0, child: Text("Center\nbottom")), ], )


1
投票

这是另一个例子,展示如何使用AlignStack使它像Stack( children: <Widget>[ Align(alignment: Alignment.center, child: Text("Center"),), Align(alignment: Alignment.topRight, child: Text("Top\nRight"),), Align(alignment: Alignment.centerRight, child: Text("Center\nRight"),), Align(alignment: Alignment.bottomRight, child: Text("Bottom\nRight"),), Align(alignment: Alignment.topLeft, child: Text("Top\nLeft"),), Align(alignment: Alignment.centerLeft, child: Text("Center\nLeft"),), Align(alignment: Alignment.bottomLeft, child: Text("Bottom\nLeft"),), Align(alignment: Alignment.topCenter, child: Text("Top\nCenter"),), Align(alignment: Alignment.bottomCenter, child: Text("Bottom\nCenter"),), Align(alignment: Alignment(0.0, 0.5), child: Text("Custom\nPostition", style: TextStyle(color: Colors.red, fontSize: 20.0, fontWeight: FontWeight.w800),),), ], ); 一样工作。

enter image description here

Stack
© www.soinside.com 2019 - 2024. All rights reserved.