如何根据屏幕尺寸调整颤振小部件的大小?
Posted
技术标签:
【中文标题】如何根据屏幕尺寸调整颤振小部件的大小?【英文标题】:How to resize flutter widgets depending on screen size? 【发布时间】:2020-08-31 03:15:45 【问题描述】:我是 Flutter 的初学者,我找到了我想使用的这个包 https://pub.dev/packages/flutter_calendar_carousel。我正在尝试将它用于颤振的网络应用程序。我去运行了这个例子,它可以工作,但是当我最大化窗口时出现问题,它看起来不太好;大圆圈,看起来和小窗口不一样(尺寸问题,缩放不好):
我尝试使用 AspectRatio 小部件,它看起来更好,但仍然很大。我不确定如何正确使用纵横比,但还有其他方法可以解决它吗? TLDR;我希望日历是可读的,并且可以根据屏幕的大小进行缩放。 这是示例中的代码:
import 'package:flutter_calendar_carousel/flutter_calendar_carousel.dart'
show CalendarCarousel;
import 'package:flutter_calendar_carousel/classes/event.dart';
import 'package:flutter_calendar_carousel/classes/event_list.dart';
import 'package:intl/intl.dart' show DateFormat;
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget
// This widget is the root of your application.
@override
Widget build(BuildContext context)
return new MaterialApp(
title: 'dooboolab flutter calendar',
theme: new ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or press Run > Flutter Hot Reload in IntelliJ). Notice that the
// counter didn't reset back to zero; the application is not restarted.
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Calendar Carousel Example'),
);
class MyHomePage extends StatefulWidget
MyHomePage(Key key, this.title) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
DateTime _currentDate = DateTime(2019, 2, 3);
DateTime _currentDate2 = DateTime(2019, 2, 3);
String _currentMonth = DateFormat.yMMM().format(DateTime(2019, 2, 3));
DateTime _targetDateTime = DateTime(2019, 2, 3);
// List<DateTime> _markedDate = [DateTime(2018, 9, 20), DateTime(2018, 10, 11)];
static Widget _eventIcon = new Container(
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(1000)),
border: Border.all(color: Colors.blue, width: 2.0)),
child: new Icon(
Icons.person,
color: Colors.amber,
),
);
EventList<Event> _markedDateMap = new EventList<Event>(
events:
new DateTime(2019, 2, 10): [
new Event(
date: new DateTime(2019, 2, 10),
title: 'Event 1',
icon: _eventIcon,
dot: Container(
margin: EdgeInsets.symmetric(horizontal: 1.0),
color: Colors.red,
height: 5.0,
width: 5.0,
),
),
new Event(
date: new DateTime(2019, 2, 10),
title: 'Event 2',
icon: _eventIcon,
),
new Event(
date: new DateTime(2019, 2, 10),
title: 'Event 3',
icon: _eventIcon,
),
],
,
);
CalendarCarousel _calendarCarousel, _calendarCarouselNoHeader;
@override
void initState()
/// Add more events to _markedDateMap EventList
_markedDateMap.add(
new DateTime(2019, 2, 25),
new Event(
date: new DateTime(2019, 2, 25),
title: 'Event 5',
icon: _eventIcon,
));
_markedDateMap.add(
new DateTime(2019, 2, 10),
new Event(
date: new DateTime(2019, 2, 10),
title: 'Event 4',
icon: _eventIcon,
));
_markedDateMap.addAll(new DateTime(2019, 2, 11), [
new Event(
date: new DateTime(2019, 2, 11),
title: 'Event 1',
icon: _eventIcon,
),
new Event(
date: new DateTime(2019, 2, 11),
title: 'Event 2',
icon: _eventIcon,
),
new Event(
date: new DateTime(2019, 2, 11),
title: 'Event 3',
icon: _eventIcon,
),
]);
super.initState();
@override
Widget build(BuildContext context)
/// Example with custom icon
_calendarCarousel = CalendarCarousel<Event>(
onDayPressed: (DateTime date, List<Event> events)
this.setState(() => _currentDate = date);
events.forEach((event) => print(event.title));
,
weekendTextStyle: TextStyle(
color: Colors.red,
),
thisMonthDayBorderColor: Colors.grey,
// weekDays: null, /// for pass null when you do not want to render weekDays
headerText: 'Custom Header',
weekFormat: true,
markedDatesMap: _markedDateMap,
height: 200.0,
selectedDateTime: _currentDate2,
showIconBehindDayText: true,
// daysHaveCircularBorder: false, /// null for not rendering any border, true for circular border, false for rectangular border
customGridViewPhysics: NeverScrollableScrollPhysics(),
markedDateShowIcon: true,
markedDateIconMaxShown: 2,
selectedDayTextStyle: TextStyle(
color: Colors.yellow,
),
todayTextStyle: TextStyle(
color: Colors.blue,
),
markedDateIconBuilder: (event)
return event.icon;
,
minSelectedDate: _currentDate.subtract(Duration(days: 360)),
maxSelectedDate: _currentDate.add(Duration(days: 360)),
todayButtonColor: Colors.transparent,
todayBorderColor: Colors.green,
markedDateMoreShowTotal:
true, // null for not showing hidden events indicator
// markedDateIconMargin: 9,
// markedDateIconOffset: 3,
);
/// Example Calendar Carousel without header and custom prev & next button
_calendarCarouselNoHeader = CalendarCarousel<Event>(
todayBorderColor: Colors.green,
onDayPressed: (DateTime date, List<Event> events)
this.setState(() => _currentDate2 = date);
events.forEach((event) => print(event.title));
,
daysHaveCircularBorder: true,
showOnlyCurrentMonthDate: false,
weekendTextStyle: TextStyle(
color: Colors.red,
),
thisMonthDayBorderColor: Colors.grey,
weekFormat: false,
// firstDayOfWeek: 4,
markedDatesMap: _markedDateMap,
height: 420.0,
selectedDateTime: _currentDate2,
targetDateTime: _targetDateTime,
customGridViewPhysics: NeverScrollableScrollPhysics(),
markedDateCustomShapeBorder: CircleBorder(
side: BorderSide(color: Colors.yellow)
),
markedDateCustomTextStyle: TextStyle(
fontSize: 18,
color: Colors.blue,
),
showHeader: false,
todayTextStyle: TextStyle(
color: Colors.blue,
),
// markedDateShowIcon: true,
// markedDateIconMaxShown: 2,
// markedDateIconBuilder: (event)
// return event.icon;
// ,
// markedDateMoreShowTotal:
// true,
todayButtonColor: Colors.yellow,
selectedDayTextStyle: TextStyle(
color: Colors.yellow,
),
minSelectedDate: _currentDate.subtract(Duration(days: 360)),
maxSelectedDate: _currentDate.add(Duration(days: 360)),
prevDaysTextStyle: TextStyle(
fontSize: 16,
color: Colors.pinkAccent,
),
inactiveDaysTextStyle: TextStyle(
color: Colors.tealAccent,
fontSize: 16,
),
onCalendarChanged: (DateTime date)
this.setState(()
_targetDateTime = date;
_currentMonth = DateFormat.yMMM().format(_targetDateTime);
);
,
onDayLongPressed: (DateTime date)
print('long pressed date $date');
,
);
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
//custom icon
Container(
margin: EdgeInsets.symmetric(horizontal: 16.0),
child: _calendarCarousel,
), // This trailing comma makes auto-formatting nicer for build methods.
//custom icon without header
Container(
margin: EdgeInsets.only(
top: 30.0,
bottom: 16.0,
left: 16.0,
right: 16.0,
),
child: new Row(
children: <Widget>[
Expanded(
child: Text(
_currentMonth,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 24.0,
),
)),
FlatButton(
child: Text('PREV'),
onPressed: ()
setState(()
_targetDateTime = DateTime(_targetDateTime.year, _targetDateTime.month -1);
_currentMonth = DateFormat.yMMM().format(_targetDateTime);
);
,
),
FlatButton(
child: Text('NEXT'),
onPressed: ()
setState(()
_targetDateTime = DateTime(_targetDateTime.year, _targetDateTime.month +1);
_currentMonth = DateFormat.yMMM().format(_targetDateTime);
);
,
)
],
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 16.0),
child: _calendarCarouselNoHeader,
), //
],
),
));
```
【问题讨论】:
使用MediaQuery.of(context).size.width
和 MediaQuery.of(context).size.height
值分别获取屏幕宽度和高度,并相应地调整小部件的大小
这能回答你的问题吗? How to make flutter app responsive according to different screen size?
@LoVe 我的问题是在示例中我会在哪里使用它?
【参考方案1】:
您可以使用LayoutBuilder
获取父窗口小部件的尺寸并调整子窗口小部件的尺寸以适应。
从您的示例中,我添加了高度和宽度参数要求来创建 calendarCarousel 小部件。日历小部件上使用的高度和宽度参数来自LayoutBuilder
。
每次调整浏览器窗口大小时,Flutter 都会调用Widget build()
重建屏幕,从而重建 UI。
完整代码
import 'package:flutter/material.dart';
import 'package:flutter_calendar_carousel/flutter_calendar_carousel.dart'
show CalendarCarousel;
import 'package:flutter_calendar_carousel/classes/event.dart';
import 'package:flutter_calendar_carousel/classes/event_list.dart';
import 'package:intl/intl.dart' show DateFormat;
void main()
runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return new MaterialApp(
title: 'dooboolab flutter calendar',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Calendar Carousel Example'),
);
class MyHomePage extends StatefulWidget
MyHomePage(Key key, this.title) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
DateTime _currentDate = DateTime(2019, 2, 3);
DateTime _currentDate2 = DateTime(2019, 2, 3);
String _currentMonth = DateFormat.yMMM().format(DateTime(2019, 2, 3));
DateTime _targetDateTime = DateTime(2019, 2, 3);
// List<DateTime> _markedDate = [DateTime(2018, 9, 20), DateTime(2018, 10, 11)];
static Widget _eventIcon = new Container(
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(1000)),
border: Border.all(color: Colors.blue, width: 2.0)),
child: new Icon(
Icons.person,
color: Colors.amber,
),
);
EventList<Event> _markedDateMap = new EventList<Event>(
events:
new DateTime(2019, 2, 10): [
new Event(
date: new DateTime(2019, 2, 10),
title: 'Event 1',
icon: _eventIcon,
dot: Container(
margin: EdgeInsets.symmetric(horizontal: 1.0),
color: Colors.red,
height: 5.0,
width: 5.0,
),
),
new Event(
date: new DateTime(2019, 2, 10),
title: 'Event 2',
icon: _eventIcon,
),
new Event(
date: new DateTime(2019, 2, 10),
title: 'Event 3',
icon: _eventIcon,
),
],
,
);
// CalendarCarousel _calendarCarousel, _calendarCarouselNoHeader;
@override
void initState()
/// Add more events to _markedDateMap EventList
_markedDateMap.add(
new DateTime(2019, 2, 25),
new Event(
date: new DateTime(2019, 2, 25),
title: 'Event 5',
icon: _eventIcon,
));
_markedDateMap.add(
new DateTime(2019, 2, 10),
new Event(
date: new DateTime(2019, 2, 10),
title: 'Event 4',
icon: _eventIcon,
));
_markedDateMap.addAll(new DateTime(2019, 2, 11), [
new Event(
date: new DateTime(2019, 2, 11),
title: 'Event 1',
icon: _eventIcon,
),
new Event(
date: new DateTime(2019, 2, 11),
title: 'Event 2',
icon: _eventIcon,
),
new Event(
date: new DateTime(2019, 2, 11),
title: 'Event 3',
icon: _eventIcon,
),
]);
super.initState();
_calendarCarousel(double calendarHeight, double calendarWidth)
return CalendarCarousel<Event>(
onDayPressed: (DateTime date, List<Event> events)
this.setState(() => _currentDate = date);
events.forEach((event) => print(event.title));
,
weekendTextStyle: TextStyle(
color: Colors.red,
),
thisMonthDayBorderColor: Colors.grey,
// weekDays: null, /// for pass null when you do not want to render weekDays
headerText: 'Custom Header',
weekFormat: true,
markedDatesMap: _markedDateMap,
height: calendarHeight,
width: calendarWidth,
selectedDateTime: _currentDate2,
showIconBehindDayText: true,
// daysHaveCircularBorder: false, /// null for not rendering any border, true for circular border, false for rectangular border
customGridViewPhysics: NeverScrollableScrollPhysics(),
markedDateShowIcon: true,
markedDateIconMaxShown: 2,
selectedDayTextStyle: TextStyle(
color: Colors.yellow,
),
todayTextStyle: TextStyle(
color: Colors.blue,
),
markedDateIconBuilder: (event)
return event.icon;
,
minSelectedDate: _currentDate.subtract(Duration(days: 360)),
maxSelectedDate: _currentDate.add(Duration(days: 360)),
todayButtonColor: Colors.transparent,
todayBorderColor: Colors.green,
markedDateMoreShowTotal:
true, // null for not showing hidden events indicator
// markedDateIconMargin: 9,
// markedDateIconOffset: 3,
);
_calendarCarouselNoHeader(double calendarHeight, double calendarWidth)
return CalendarCarousel<Event>(
todayBorderColor: Colors.green,
onDayPressed: (DateTime date, List<Event> events)
this.setState(() => _currentDate2 = date);
events.forEach((event) => print(event.title));
,
daysHaveCircularBorder: true,
showOnlyCurrentMonthDate: false,
weekendTextStyle: TextStyle(
color: Colors.red,
),
thisMonthDayBorderColor: Colors.grey,
weekFormat: false,
// firstDayOfWeek: 4,
markedDatesMap: _markedDateMap,
height: calendarHeight,
width: calendarWidth,
selectedDateTime: _currentDate2,
targetDateTime: _targetDateTime,
customGridViewPhysics: NeverScrollableScrollPhysics(),
markedDateCustomShapeBorder:
CircleBorder(side: BorderSide(color: Colors.yellow)),
markedDateCustomTextStyle: TextStyle(
fontSize: 18,
color: Colors.blue,
),
showHeader: false,
todayTextStyle: TextStyle(
color: Colors.blue,
),
// markedDateShowIcon: true,
// markedDateIconMaxShown: 2,
// markedDateIconBuilder: (event)
// return event.icon;
// ,
// markedDateMoreShowTotal:
// true,
todayButtonColor: Colors.yellow,
selectedDayTextStyle: TextStyle(
color: Colors.yellow,
),
minSelectedDate: _currentDate.subtract(Duration(days: 360)),
maxSelectedDate: _currentDate.add(Duration(days: 360)),
prevDaysTextStyle: TextStyle(
fontSize: 16,
color: Colors.pinkAccent,
),
inactiveDaysTextStyle: TextStyle(
color: Colors.tealAccent,
fontSize: 16,
),
onCalendarChanged: (DateTime date)
this.setState(()
_targetDateTime = date;
_currentMonth = DateFormat.yMMM().format(_targetDateTime);
);
,
onDayLongPressed: (DateTime date)
print('long pressed date $date');
,
);
@override
Widget build(BuildContext context)
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: Container(
// use LayoutBuilder to fetch the parent widget's constraints
child: LayoutBuilder(
builder: (context, constraints)
var parentHeight = constraints.maxHeight;
var parentWidth = constraints.maxWidth;
debugPrint('Max height: $parentHeight, max width: $parentWidth');
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
//custom icon
Container(
margin: EdgeInsets.symmetric(horizontal: 16.0),
// set calendar widget size percentage
child: _calendarCarousel(parentHeight * 0.2, parentWidth),
),
//custom icon without header
Container(
margin: EdgeInsets.only(
top: 30.0,
bottom: 16.0,
left: 16.0,
right: 16.0,
),
child: new Row(
children: <Widget>[
Expanded(
child: Text(
_currentMonth,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 24.0,
),
)),
FlatButton(
child: Text('PREV'),
onPressed: ()
setState(()
_targetDateTime = DateTime(_targetDateTime.year,
_targetDateTime.month - 1);
_currentMonth =
DateFormat.yMMM().format(_targetDateTime);
);
,
),
FlatButton(
child: Text('NEXT'),
onPressed: ()
setState(()
_targetDateTime = DateTime(_targetDateTime.year,
_targetDateTime.month + 1);
_currentMonth =
DateFormat.yMMM().format(_targetDateTime);
);
,
)
],
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 16.0),
// set calendar widget size percentage
child: _calendarCarouselNoHeader(parentHeight * 0.8, parentWidth),
), //
],
),
);
,
),
),
);
更新:你也可以使用MediaQuery来实现类似的功能。
@override
Widget build(BuildContext context)
var screenSize = MediaQuery.of(context).size ;
if (screenSize.width > layoutSize)
return Widget();
else
return Widget(); /// Widget if doesn't match the size
【讨论】:
以上是关于如何根据屏幕尺寸调整颤振小部件的大小?的主要内容,如果未能解决你的问题,请参考以下文章