Is there any built in widget in flutter to implement a widget like(red border in picture below) ?
which we can drag it change the value.
That's simply a horizontal ListView with predefined height.
SizedBox(
height: 56, // height of ListView
child: ListView.builder(
scrollDirection: Axis.horizontal, // makes it scroll in horizontal direction
itemBuilder: (_, index) {
// build your years
},
),
)
The desired output can be brought using the ListView.
Flutter just uploaded a video on ListView in which you can find your answer:
https://www.youtube.com/watch?v=KJpkjHGiI5A
Example code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
bool change ;
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int i=0;
void fxn(){
setState(() {
i++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('List View'),),
body: ListView.builder(
itemCount: 30,
itemBuilder: (_, index)=>Padding(
padding: const EdgeInsets.fromLTRB(0, 270, 0, 270),
child: MaterialButton(
child:
Text('200$index',style: TextStyle(fontSize: 25),),
onPressed: (){
},
color: Colors.white70,
),
),
scrollDirection: Axis.horizontal,
)
);
}
}
Output: Output
Related
The issue is on web when we try to scroll the vertically scrollable widget which is a child of horizontally scrollable widget where scroll bar is always visible.
When we scroll the horizontally scrollable widget the scroll bar for horizontal scroll is correctly displayed as shown in picture
horizontal scroll
But when we scroll the vertically scrollable widget the horizontal scrollbar disappears and new vertical scroll bar is seen at right as shown in screenshot
vertical scroll
Code to reproduce the issue.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Scroll Issue Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Scroll Issue Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController _horizontalController = ScrollController();
final List<ScrollController> _verticalController = [];
#override
void initState() {
super.initState();
for (int i = 0; i < 6; i++) {
_verticalController.add(ScrollController());
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Row(
children: <Widget>[
Expanded(
child: _buildHorizontalScroll(),
)
],
),
);
}
Widget _buildHorizontalScroll() {
return Scrollbar(
isAlwaysShown: true,
controller: _horizontalController,
notificationPredicate: (predicate) {
return predicate.depth == 0;
},
child: ListView.separated(
controller: _horizontalController,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => Container(
margin: const EdgeInsets.all(30),
width: 300,
color: Colors.black12,
child: Column(
children: [
Expanded(
child: _buildVerticalScroll(index),
)
],
),
),
separatorBuilder: (context, index) => const Divider(
height: 30,
),
itemCount: 6),
);
}
Widget _buildVerticalScroll(int index) {
return Scrollbar(
scrollbarOrientation: ScrollbarOrientation.right,
isAlwaysShown: true,
controller: _verticalController[index],
child: ListView.separated(
controller: _verticalController[index],
itemBuilder: (context, index) => Container(
margin: const EdgeInsets.all(30),
height: 100,
color: Colors.green,
),
separatorBuilder: (context, index) => const Divider(
height: 30,
),
itemCount: 200),
);
}
}
Checking the notification predicate in the horizontal scroll bar, it detects the depth of scroll as both 0 and 1 when scrolling the vertically scrollable list. Is there a workaround for this problem? The problem started to appear since the upgrade to 2.5.0 for stable channel of flutter.
Maybe this package will help you easily customize your thumb and scrolling track both horizontally and vertically
https://pub.dev/packages/cross_scroll
I'm unable to access the scrollContoller in the ListView.builder. I think its because it's below SingleChildScrollView (when I remove SingleChildScrollView I start getting print statements from the listener attached to the scrollController ). I need to access the offset from scrollController in the ListView.builder but not sure how to do so. Here's a minimum example. How would I get the listener printing from the controller in the listView..
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
ScrollController scrollController = ScrollController();
#override
void initState() {
scrollController.addListener(() {
print("Why am I not getting print statements....");
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0.0,
),
body: SingleChildScrollView(
child: Column(
children: [
Container(
width: MediaQuery.of(context).size.width,
height: 400,
color: Colors.orange,
),
ListView.builder(
controller: scrollController,
physics: ScrollPhysics(),
shrinkWrap: true,
itemCount: 30,
itemBuilder: (context, index) {
return Container(
color: Colors.primaries[index % Colors.primaries.length].withOpacity(0.5),
child: ListTile(
title: Text('Item $index'),
),
);
},
),
],
),
),
);
}
}
void main() {
runApp(MaterialApp(home: HomePage()));
}
I've a initialScrollOffset in my ScrollController set to 100. This allows the top of my ListView in my Scaffold body to appear under my appBar. (Desired behaviour, my appbar is transparent). This works fine when the page first loads but I'd like my ScrollController to prevent my listView from ever scrolling between 0 and 100 and always have an initialScrollOffset of 100. ScrollController has a boolean property keepScrollOffset` but that doesn't prevent the scroll going from 0-100. Here is my code so far:
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
ScrollController _scrollController;
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Container(
color: Colors.blue.withOpacity(0.25),
child: ListView.builder(
itemCount: 30,
itemBuilder: (context, index) {
return Container(
color: Colors.primaries[index % Colors.primaries.length].withOpacity(0.5),
child: ListTile(
title: Text('Item $index'),
),
);
},
controller: _scrollController,
),
),
);
}
#override
void initState() {
_scrollController = ScrollController(initialScrollOffset: 100, keepScrollOffset: true)
..addListener(() {
print("offset = ${_scrollController.offset}");
});
super.initState();
}
}
void main() {
runApp(MaterialApp(home: HomePage()));
}
If you want to add padding to the inner content that scrolls up and down with the items, you can just add padding to the ListView.
padding: EdgeInsets.only(top: 100)
Not necessary to use ScrollController.
I am attempting to put a ListView.builder widgets in a Column widget however the common solution provided by the flutter team is to place the unbounded ListView.builder in a Expanded or Flexible widget. The problem with this is the ListView.builder now fills as much space as it can in the column (as seen bellow).
Is there a way to have the ListView.builder only take up the space it requires?
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
// This widget is the root of your application.
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Text> lst = [Text('first'), Text('second')];
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter ListView',
home: SafeArea(
child: Scaffold(
body: Column(
children: <Widget>[
Flexible(
child: ListView.builder(
itemCount: lst.length,
itemBuilder: (context, index) {
return Center(
child: lst[index],
);
},
),
),
FlatButton(
color: Colors.blue,
child: Text("Add Third"),
onPressed: () {
setState(() {
lst.add(Text("Third"));
});
},
),
Text("Next Item"),
],
),
),
),
);
}
}
You can use shrinkWrap: true property of listview to limit the list view size.
child: ListView.builder(
shrinkWrap: true, //added line
itemCount: lst.length,
I would like to create my own safe area view but instead of just cutting off the overflown area, I would like to have the overflowing area blocked by a semi transparent background.
I realise this question is somewhat similar to Allowing a widget to overflow to another widget but the answer there can solve that question in particular but not mine.
So how do I make the flutter widget overflow?
I used stack to place a container above the view when there's a top overflow and below if there's a bottom overflow. The result works good except that its overflowing to the semi transparent background.
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Didian',
home: Scaffold(
body: OpacitySafeArea(
child: RandomWords()
),
),
);
}
}
class OpacitySafeArea extends StatelessWidget {
final Widget child;
OpacitySafeArea({
#required this.child
});
#override
Widget build(BuildContext context) {
var deviceData = MediaQuery.of(context);
var height = deviceData.size.height;
var width = deviceData.size.width;
var top = deviceData.padding.top;
var bottom = deviceData.padding.bottom;
print(deviceData);
return Stack(
overflow: Overflow.visible,
children: <Widget>[
this.child,
top > 0? Container(
color: Color.fromRGBO(255, 255, 255, 0.9),
height: top,
width: width
):null,
bottom > 0? Positioned(
bottom: 0,
child: Container(
color: Color.fromRGBO(255, 255, 255, 0.9),
height: bottom,
width: width
)
):null
].where((child) => child != null).toList()
);
}
}
class RandomWordsState extends State<RandomWords> {
final _suggestions = <WordPair>[];
Widget buildSuggestions() {
return ListView.separated(
padding: EdgeInsets.all(16),
itemCount: 100,
itemBuilder: (context, index) {
if(index >= _suggestions.length) {
_suggestions.add(WordPair.random());
}
return ListTile(
title: Text(
_suggestions[index].asPascalCase,
style: TextStyle(fontSize: 18)
)
);
},
separatorBuilder: (context, index) => Divider(),
);
}
#override
Widget build(BuildContext context) {
return buildSuggestions();
}
}
class RandomWords extends StatefulWidget {
#override
RandomWordsState createState() => RandomWordsState();
}
I was looking for same, and finally used a simple solution without using SafeArea():
Just apply a padding to ListView itself, which you can get using MediaQuery.of(context).viewPadding.bottom
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
padding: EdgeInsets.all(0).copyWith(bottom: MediaQuery.of(context).viewPadding.bottom),
itemCount: 2000,
itemBuilder: (BuildContext context, int index) {
return Text("Item: $index");
},
),
);
}