Flutter 如何在同一页面中导航母版详细信息页面颤振
我正在构建一个基于主细节的应用程序,我想在splitview中显示。试图了解如何将数据推送到同一视图中的另一页,但无法。希望在第二页中包含详细信息数据。如何推送数据 它可能是响应性的,也可能不是。但我不想解决,但只使用SET状态并在细节页面中填充空白Flutter 如何在同一页面中导航母版详细信息页面颤振,flutter,layout,flutter-layout,master-detail,Flutter,Layout,Flutter Layout,Master Detail,我正在构建一个基于主细节的应用程序,我想在splitview中显示。试图了解如何将数据推送到同一视图中的另一页,但无法。希望在第二页中包含详细信息数据。如何推送数据 它可能是响应性的,也可能不是。但我不想解决,但只使用SET状态并在细节页面中填充空白 类MyHomePage扩展StatefulWidget{ MyHomePage({Key,this.title}):超级(Key:Key); 最后的字符串标题; @凌驾 _MyHomePageState createState()=>\u MyH
类MyHomePage扩展StatefulWidget{
MyHomePage({Key,this.title}):超级(Key:Key);
最后的字符串标题;
@凌驾
_MyHomePageState createState()=>\u MyHomePageState();
}
类_MyHomePageState扩展状态{
@凌驾
void initState(){
super.initState();
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(
标题:正文(
widget.title,
样式:TextStyle(颜色:Colors.black),
),
背景颜色:颜色。透明,
海拔:0,
),
主体:填充物(
填充:常数边集全部(8.0),
子:垂直拆分视图(
左:ListView.builder(itemCount:12,
itemBuilder:(上下文,索引){
回程卡(
孩子:InkWell(
飞溅颜色:颜色。蓝色。带有alpha(30),
onTap:(){
//push(context,MaterialPageRoute(builder:(context)=>newyapiekle());
},
子:容器(
孩子:填充(
填充:所有边缘设置(12.0),
孩子:排(
mainAxisAlignment:mainAxisAlignment.center,
//将列内容垂直居中,
crossAxisAlignment:crossAxisAlignment.center,
儿童:[
扩大(
孩子:ListTile(
前导:Image.network(“https://picsum.photos/200/300"),
标题:文本(“标题”),
字幕:文本(“字幕”),
),
//垫片(),
],
),
),
),
),
);
}
),
右:集装箱(
装饰:盒子装饰(
边框:边框。全部(颜色:颜色。黑色),
),
儿童:中心(
孩子:我的标志(
尺码:256,
)),
),
),
),
);
}
}
类VerticalSplitView扩展StatefulWidget{
最后一个小部件离开;
最终权利;
最终倍率;
常量垂直拆分视图(
{Key Key,@required this.left,@required this.right,this.ratio=0.5})
:assert(左!=null),
断言(右!=null),
断言(比率>=0),
断言(比率_VerticalSplitViewState();
}
类_VerticalSplitViewState扩展状态{
最终分割宽度=16.0;
//从0-1
双u比;
双最大宽度;
获取_width1=>_ratio*_maxWidth;
获取_width2=>(1-_比率)*\u maxWidth;
@凌驾
void initState(){
super.initState();
_ratio=widget.ratio;
}
@凌驾
小部件构建(构建上下文){
返回LayoutBuilder(生成器:(上下文,框约束){
断言(_比率=0);
如果(_maxWidth==null)_maxWidth=constraints.maxWidth-_dividerWidth;
if(_maxWidth!=constraints.maxWidth){
_maxWidth=constraints.maxWidth-\u dividerWidth;
}
返回大小框(
宽度:constraints.maxWidth,
孩子:排(
儿童:[
大小盒子(
宽度:_宽度1,
孩子:widget.left,
),
手势检测器(
行为:HitTestBehavior.transparent,
孩子:大小盒子(
宽度:_分隔宽度,
高度:constraints.maxHeight,
子:旋转变换(
子:图标(图标。拖动手柄),
转弯:始终停止转弯(0.25),
),
),
onPanUpdate:(DragUpdate详细信息){
设置状态(){
_比率+=details.delta.dx/_maxWidth;
如果(_比率>1)
_比率=1;
否则,如果(_比率<0.0)_比率=0.0;
});
},
),
大小盒子(
宽度:_宽度2,
孩子:对,
),
],
),
);
});
}
}
我假设您希望通过单击左边的卡片小部件来更改右边的页面。我已经开发了类似的东西。我正在使用IndexedStack
在VerticalSplitView
的右边进行渲染,然后使用提供者和使用者来控制页面的显示
首先,您需要在pubspec.ymal中导入依赖项
您可以将下面的代码替换为整个main.dart
在main.dart中,您可以尝试替换此代码。我们的想法是创建包含小部件的IndexedStack
(您喜欢的页面)。然后,我们将使用提供程序和消费者更改IndexedStack
的索引
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_indexed_stack/page_data.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) {
var pageData = PageData();
return pageData;
}),
],
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// Set required page same as list length in left of VerticalSplitView
List<Widget> pages = [Text('Page1'), Text('Page2'), Text('Page3'),
Text('Page4'), Text('Page5'), Text('Page6'), Text('Page7'),
Text('Page8'), Text('Page9'), Text('Page10'), Text('Page11'),
Text('Page12'), ];
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.title,
style: TextStyle(color: Colors.black),
),
backgroundColor: Colors.transparent,
elevation: 0,
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: VerticalSplitView(
left: ListView.builder( itemCount: 12,
itemBuilder: (context, index) {
return Card(
child: InkWell(
splashColor: Colors.blue.withAlpha(30),
onTap: () {
// Set the current page for change page on the right side.
Provider.of<PageData>(context, listen: false).setCurrentTab(index);
},
child: Container(
child: Padding(
padding: EdgeInsets.all(12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
//Center Column contents vertically,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: ListTile(
leading: Image.network("https://picsum.photos/200/300"),
title: Text("Title"),
subtitle: Text("Subtitle")),
),
//Spacer(),
],
),
),
),
),
);
}
),
right: Consumer<PageData>(
builder: (context, pageData, child) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
),
child: IndexedStack(
children: pages,
index: pageData.currentPage,
)
);
},
),
),
),
);
}
}
class VerticalSplitView extends StatefulWidget {
final Widget left;
final Widget right;
final double ratio;
const VerticalSplitView(
{Key key, @required this.left, @required this.right, this.ratio = 0.5})
: assert(left != null),
assert(right != null),
assert(ratio >= 0),
assert(ratio <= 1),
super(key: key);
@override
_VerticalSplitViewState createState() => _VerticalSplitViewState();
}
class _VerticalSplitViewState extends State<VerticalSplitView> {
final _dividerWidth = 16.0;
//from 0-1
double _ratio;
double _maxWidth;
get _width1 => _ratio * _maxWidth;
get _width2 => (1 - _ratio) * _maxWidth;
@override
void initState() {
super.initState();
_ratio = widget.ratio;
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, BoxConstraints constraints) {
assert(_ratio <= 1);
assert(_ratio >= 0);
if (_maxWidth == null) _maxWidth = constraints.maxWidth - _dividerWidth;
if (_maxWidth != constraints.maxWidth) {
_maxWidth = constraints.maxWidth - _dividerWidth;
}
return SizedBox(
width: constraints.maxWidth,
child: Row(
children: <Widget>[
SizedBox(
width: _width1,
child: widget.left,
),
GestureDetector(
behavior: HitTestBehavior.translucent,
child: SizedBox(
width: _dividerWidth,
height: constraints.maxHeight,
child: RotationTransition(
child: Icon(Icons.drag_handle),
turns: AlwaysStoppedAnimation(0.25),
),
),
onPanUpdate: (DragUpdateDetails details) {
setState(() {
_ratio += details.delta.dx / _maxWidth;
if (_ratio > 1)
_ratio = 1;
else if (_ratio < 0.0) _ratio = 0.0;
});
},
),
SizedBox(
width: _width2,
child: widget.right,
),
],
),
);
});
}
}
快乐编码:)
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_indexed_stack/page_data.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) {
var pageData = PageData();
return pageData;
}),
],
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// Set required page same as list length in left of VerticalSplitView
List<Widget> pages = [Text('Page1'), Text('Page2'), Text('Page3'),
Text('Page4'), Text('Page5'), Text('Page6'), Text('Page7'),
Text('Page8'), Text('Page9'), Text('Page10'), Text('Page11'),
Text('Page12'), ];
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.title,
style: TextStyle(color: Colors.black),
),
backgroundColor: Colors.transparent,
elevation: 0,
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: VerticalSplitView(
left: ListView.builder( itemCount: 12,
itemBuilder: (context, index) {
return Card(
child: InkWell(
splashColor: Colors.blue.withAlpha(30),
onTap: () {
// Set the current page for change page on the right side.
Provider.of<PageData>(context, listen: false).setCurrentTab(index);
},
child: Container(
child: Padding(
padding: EdgeInsets.all(12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
//Center Column contents vertically,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: ListTile(
leading: Image.network("https://picsum.photos/200/300"),
title: Text("Title"),
subtitle: Text("Subtitle")),
),
//Spacer(),
],
),
),
),
),
);
}
),
right: Consumer<PageData>(
builder: (context, pageData, child) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
),
child: IndexedStack(
children: pages,
index: pageData.currentPage,
)
);
},
),
),
),
);
}
}
class VerticalSplitView extends StatefulWidget {
final Widget left;
final Widget right;
final double ratio;
const VerticalSplitView(
{Key key, @required this.left, @required this.right, this.ratio = 0.5})
: assert(left != null),
assert(right != null),
assert(ratio >= 0),
assert(ratio <= 1),
super(key: key);
@override
_VerticalSplitViewState createState() => _VerticalSplitViewState();
}
class _VerticalSplitViewState extends State<VerticalSplitView> {
final _dividerWidth = 16.0;
//from 0-1
double _ratio;
double _maxWidth;
get _width1 => _ratio * _maxWidth;
get _width2 => (1 - _ratio) * _maxWidth;
@override
void initState() {
super.initState();
_ratio = widget.ratio;
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, BoxConstraints constraints) {
assert(_ratio <= 1);
assert(_ratio >= 0);
if (_maxWidth == null) _maxWidth = constraints.maxWidth - _dividerWidth;
if (_maxWidth != constraints.maxWidth) {
_maxWidth = constraints.maxWidth - _dividerWidth;
}
return SizedBox(
width: constraints.maxWidth,
child: Row(
children: <Widget>[
SizedBox(
width: _width1,
child: widget.left,
),
GestureDetector(
behavior: HitTestBehavior.translucent,
child: SizedBox(
width: _dividerWidth,
height: constraints.maxHeight,
child: RotationTransition(
child: Icon(Icons.drag_handle),
turns: AlwaysStoppedAnimation(0.25),
),
),
onPanUpdate: (DragUpdateDetails details) {
setState(() {
_ratio += details.delta.dx / _maxWidth;
if (_ratio > 1)
_ratio = 1;
else if (_ratio < 0.0) _ratio = 0.0;
});
},
),
SizedBox(
width: _width2,
child: widget.right,
),
],
),
);
});
}
}
class PageData extends ChangeNotifier{
PageData();
int _currentPage = 0;
void setCurrentTab(int index){
this._currentPage = index;
notifyListeners();
}
int get currentPage {
return this._currentPage;
}
}