我想实现此视频中的布局(在5:50时)https://www.youtube.com/watch?v=KYUTQQ1usZE&index=1&list=PL23Revp-82LKxKN9SXqQ5Nxaa1ZpYEQuaadd#t=05m50s
您将如何解决?我尝试使用ListView&GridLayout,但这似乎仅限于存档。我是否需要使用CustomMultiChildLayout(https://docs.flutter.io/flutter/widgets/CustomMultiChildLayout-class.html)或CustomScrollView(https://docs.flutter.io/flutter/widgets/CustomScrollView-class.html)之类的东西?
任何建议,将不胜感激,谢谢:)
更新:
据我所知,我将需要使用CustomScrollView(如果我错了,请纠正我)。但是Flutter框架给我留下的选择让我有些不知所措。而且我从文档中不确定要扩展我的目标需要扩展哪些类或需要实现哪些接口(interface)。我不知道我需要深入框架。具有自定义滚动效果的条和列表涉及以下类:
SliverMultiBoxAdaptorElement实现RenderSliverBoxChildManager。因此,RenderSliverList和SliverMultiBoxAdaptorElement是RenderSliverMultiBoxAdaptor和RenderSliverBoxChildManager的具体实现。我以为我可以扩展这些类(class)。但是,如果这样做,我仍然必须重新实现performLayout方法。因此,也许可以重用SliverMultiBoxAdaptorElement并扩展RenderSliverMultiBoxAdaptor?
那么,我真的必须扩展RenderSliverMultiBoxAdaptor并自己实现perfromLayout方法吗?对我来说,这似乎是唯一的选择...
最佳答案
乍一看很难理解条状逻辑。
但是重要的是SliverGeometry类
固定在屏幕上时,您需要从顶部 push 它。
小部件。
知道您滚动了所有条子。
import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: MyHomePage(),
),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey _key = GlobalKey();
RenderObject ansestor;
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback(_getPosition);
super.initState();
}
_getPosition(_) {
setState(() {
ansestor = _key.currentContext.findRenderObject();
});
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
return CustomScrollView(
physics: ClampingScrollPhysics(),
key: _key,
slivers: <Widget>[
CustomSliver(
isInitiallyExpanded: true,
ansestor: ansestor,
child: _Item(
title: 'first title',
fileName: 'item_1',
),
),
CustomSliver(
ansestor: ansestor,
child: _Item(
title: 'second title',
fileName: 'item_2',
),
),
CustomSliver(
ansestor: ansestor,
child: _Item(
title: 'third title',
fileName: 'item_3',
),
),
CustomSliver(
ansestor: ansestor,
child: _Item(
title: 'fourth title',
fileName: 'item_4',
),
),
CustomSliver(
ansestor: ansestor,
child: _Item(
title: 'fifth title',
fileName: 'item_5',
),
),
CustomSliver(
ansestor: ansestor,
child: _Item(
title: 'first title',
fileName: 'item_6',
),
),
SliverToBoxAdapter(
child: Container(
child: Center(
child: Text('end'),
),
height: 1200,
color: Colors.green.withOpacity(0.3),
),
),
],
);
});
}
}
class CustomSliver extends SingleChildRenderObjectWidget {
CustomSliver({
this.child,
Key key,
this.ansestor,
this.isInitiallyExpanded = false,
}) : super(key: key);
final RenderObject ansestor;
final bool isInitiallyExpanded;
@override
RenderObject createRenderObject(BuildContext context) {
return CustomRenderSliver(
isInitiallyExpanded: isInitiallyExpanded,
);
}
@override
void updateRenderObject(
BuildContext context,
CustomRenderSliver renderObject,
) {
renderObject.ansestor = ansestor;
renderObject.markNeedsLayout();
}
final Widget child;
}
class CustomRenderSliver extends RenderSliverSingleBoxAdapter {
CustomRenderSliver({
RenderBox child,
this.isInitiallyExpanded,
}) : super(child: child);
final double max = 250;
final double min = 100;
RenderObject ansestor;
final bool isInitiallyExpanded;
void performLayout() {
var constraints = this.constraints;
double distanceToTop;
double maxExtent;
if (ansestor != null) {
distanceToTop = child.localToGlobal(Offset.zero, ancestor: ansestor).dy;
}
if (ansestor == null) {
if (isInitiallyExpanded) {
maxExtent = max;
} else {
maxExtent = min;
}
} else {
if (constraints.scrollOffset > 0) {
maxExtent = (max - constraints.scrollOffset).clamp(0.0, max);
} else if (distanceToTop < max) {
maxExtent = min + (3 * (250 - distanceToTop) / 5);
} else {
maxExtent = min;
}
}
child.layout(
constraints.asBoxConstraints(maxExtent: maxExtent),
parentUsesSize: true,
);
var paintExtent = math.min(maxExtent, constraints.remainingPaintExtent);
geometry = SliverGeometry(
paintOrigin: maxExtent == 0 ? 0.0 : constraints.scrollOffset,
scrollExtent: max,
paintExtent: paintExtent,
maxPaintExtent: paintExtent,
hasVisualOverflow: true,
);
constraints = constraints.copyWith(remainingPaintExtent: double.infinity);
setChildParentData(child, constraints, geometry);
}
}
class _Item extends StatelessWidget {
const _Item({
Key key,
@required this.title,
@required this.fileName,
}) : super(key: key);
final String title;
final String fileName;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
return Container(
height: 250,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/$fileName.png'),
fit: BoxFit.fitWidth,
),
),
child: Padding(
padding: const EdgeInsets.only(top: 40),
child: Text(
title,
style: Theme.of(context).textTheme.headline4.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 60,
),
),
),
);
},
);
}
}
关于layout - flutter ,自定义滚动效果,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47979598/