#flutter #layout
#flutter #макет
Вопрос:
Я хотел бы поместить следующие виджеты в SingleChildScrollView
, но я хочу, чтобы синяя рамка располагалась прямо под сгибом при рендеринге страницы. Пользователь может прокрутить его в поле зрения по мере необходимости, но для начала он находится вне поля зрения.
Я вижу простой способ добиться этого, если бы я мог рассчитать пространство, занимаемое моими красными и зелеными полями на экране, и установить верхнее поле красного поля на оставшееся пространство. Сложность заключается в том, что высота красного и зеленого полей является динамической в зависимости от их содержимого, а также ширины полей в портретном и альбомном макетах.
Возможно, мне следует использовать SizedBox
вместо настройки поля моего красного поля, что не будет проблемой. Но мне все еще нужно иметь возможность рассчитать высоту пустого пространства в верхней части моего макета.
Комментарии:
1. проверьте
CustomMultiChildLayout
Ответ №1:
У @pskink была правильная идея. Вот что я сделал с ним в коде для достижения макета.
enum AuthWidgets { form, action, disclaimer }
class AuthLayoutDelegate extends MultiChildLayoutDelegate {
AuthLayoutDelegate({@required screenHeight}) : _screenHeight = screenHeight;
double _overlap = 50;
double _screenHeight;
@override
void performLayout(Size size) {
Size formSize;
Size actionSize;
Size disclaimerSize;
// if (formSize == null amp;amp; hasChild(AuthWidgets.form)) {
formSize = layoutChild(AuthWidgets.form, BoxConstraints.loose(size));
// }
// if (actionSize == null amp;amp; hasChild(AuthWidgets.action)) {
actionSize = layoutChild(AuthWidgets.action, BoxConstraints.loose(size));
// }
// if (disclaimerSize == null amp;amp; hasChild(AuthWidgets.disclaimer)) {
disclaimerSize =
layoutChild(AuthWidgets.disclaimer, BoxConstraints.loose(size));
// }
if (formSize != null amp;amp; actionSize != null amp;amp; disclaimerSize != null) {
print('laying out children');
// Need the height of the form and action area, minus the overlap
var aboveTheFold = formSize.height actionSize.height - _overlap;
var offsetY = _screenHeight - aboveTheFold;
offsetY = formSize.height - _overlap;
positionChild(AuthWidgets.action, Offset(0, offsetY));
offsetY = actionSize.height;
positionChild(AuthWidgets.disclaimer, Offset(0, offsetY));
positionChild(AuthWidgets.form, Offset(0, _screenHeight - aboveTheFold));
}
}
@override
bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) {
return false;
}
}
class AuthLayout extends StatelessWidget {
const AuthLayout({@required this.screenHeight, Key key}) : super(key: key);
final double screenHeight;
@override
Widget build(BuildContext context) {
return CustomMultiChildLayout(
delegate: AuthLayoutDelegate(screenHeight: screenHeight),
children: [
LayoutId(id: AuthWidgets.action, child: ActionMenu()),
LayoutId(id: AuthWidgets.disclaimer, child: Disclaimer()),
LayoutId(id: AuthWidgets.form, child: SignInForm()),
],
);
}
}
class SignInForm extends StatelessWidget {
const SignInForm({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 16),
child: Container(
color: Colors.red.withOpacity(0.5),
height: 350,
child: Center(
child: Text('SignInForm'),
),
),
);
}
}
class Disclaimer extends StatelessWidget {
const Disclaimer({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
height: 300,
color: Colors.blue.withOpacity(0.5),
child: Center(child: Text('Disclaimer')),
);
}
}
class ActionMenu extends StatelessWidget {
const ActionMenu({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
height: 200,
color: Colors.green.withOpacity(0.5),
child: Center(child: Text('ActionMenu')),
);
}
}
Используя делегат и performLayout
функцию, я смог расположить свои виджеты именно там, где они мне были нужны. Я действительно хотел, чтобы моя красная область отображалась «поверх» зеленой области, поэтому я должен был убедиться, что она была добавлена CustomMultiChildLayout
последней (или, по крайней мере, после зеленой рамки).
Теперь я изо всех сил пытаюсь заставить это прокручиваться на странице, но это вопрос для другого потока.