Strange Bug with horizontal ListView inside Vertical SliverList - dart

After scrolling vertically upwards, the horizontal ListView scrolls itself to the right.
The error only occurs when, at the time the horizontal Listview is displayed, the finger no longer touches the touchscreen and the vertical SliverList continues to run by itself.
Here is the code to reproduce the error:
Widget build(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index == 0)
return SizedBox(
height: 50,
child: ListView.builder(
itemBuilder: (context, index) => Container(
width: 200,
color: Colors.black45,
margin: const EdgeInsets.symmetric(horizontal: 8),
),
scrollDirection: Axis.horizontal,
),
);
return Container(
height: 200,
margin: const EdgeInsets.symmetric(vertical: 8),
color: Colors.black45,
);
},
),
)
],
);
}

You should add the key to your ListView.
In here, we can use key: PageStorageKey()

Related

How can you reduce the width of a RaisedButton inside a ListView.builder?

I can't seem to figure out how to reduce the width of a RaisedButton inside a ListView.builder.
ListView.builder(
itemCount: streetList.length,
itemBuilder: (context, index) {
bool first = 0 == (index);
bool last = streetList.length - 1 == (index);
EdgeInsets itemEdges = EdgeInsets.only(bottom: 20);
if (first) {
itemEdges = EdgeInsets.only(top: 50, bottom: 20);
} else if (last) {
itemEdges = EdgeInsets.only(bottom: 50);
}
return Container(
margin: EdgeInsets.symmetric(horizontal: 30),
padding: itemEdges,
child: SizedBox(
// height: 50,
child: RaisedButton(
child: Text(streetList[index]),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => StreetNumberList(
widget.peopleList, (streetList[index])),
),
);
},
),
),
);
}),
I get this:
I'm trying to reduce the width of the RaisedButtons but it seems like ListView.builder items are set to use max width all the time. How can I override that?
Thanks!
If you want the default size of the RaisedButton just add the Align widget as parent
return Container(
margin: EdgeInsets.symmetric(horizontal: 30),
padding: itemEdges,
child: Align(
child: RaisedButton(
child: Text("index: $index"),
onPressed: () {},
),
),
);
If you want to change the size use SizedBox inside Align
return Container(
margin: EdgeInsets.symmetric(horizontal: 30),
padding: itemEdges,
child: Align(
child: SizedBox(
width: 250,
child: RaisedButton(
child: Text("index: $index"),
onPressed: () {},
),
),
),
);
For more details check this: https://docs.flutter.dev/development/ui/layout/constraints

How to vertical align ListView in the middle

I want my list item in the middle of the ListView
#override Widget build(BuildContext context)
{
List<String> listName = ['Woody', 'Buzz', 'Rex'];
return Container
(
decoration: BoxDecoration(border: Border.all(color: Colors.pinkAccent)),
width: 400,
height: 700,
alignment: Alignment.centerLeft,
child: ListView.builder
(
itemCount: listName.length,
itemBuilder: (context, index)
{
return OurName(listName[index]);
},
),
);
}
This is when I use shrinkWrap, when I scroll up it's cut off and it can't be scroll down
shrinkWrap
This is what I expected expected
The key to your issue is the shrinkWrap property of ListView. So to fix this you can do something like this:
Container(
alignment: Alignment.centerLeft,
child: ListView.builder(
itemBuilder: (context, index) {
return Text("The index$index");
},
shrinkWrap: true,
itemCount: 30,
),
),
For me works this code!
#override
Widget build(BuildContext context) {
return Container(
height: double.infinity,
width: double.infinity,
alignment: Alignment.center,
child: ListView.builder(
shrinkWrap: true,
itemCount:rows.length,
itemBuilder: (
context,
index,
) {
return ...;
}),
);
}
I came here to center vertically (and horizontally) my listView, and came up with this:
#override
Widget build(BuildContext context) {
List<String> listName = ['Woody', 'Buzz', 'Rex'];
return Align(
child: ListView.builder(
itemCount: listName.length,
itemBuilder: (context, index) {
return Center(child: Text(listName[index]));
},
shrinkWrap: true,
),
);
}
i dont get what you mean do you want to align the whole listview then use a center widget and align the listview in the center, or use Align widget and manually align it by
Align(
alignment: Alignment.centerRight,
child: //here your list,
)
if thats not what you want or doesn't get the job done then please explain more.

Anchor floating action button to Card

When creating a Card (for example using the code from the Docs) , how can I anchor a FAB to the Card (the green circle in the image below), like in this question for Android.
I saw a similar question for attaching a FAB to the AppBar, but the solution relies on the AppBar being a fixed height. When using a Card, the height isn't fixed ahead of time so the same solution can't be used.
You can place the FloatingActionButton in an Align widget and play with the heightFactor property.
For example:
class MyCard extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Card(
child: Column(
children: <Widget>[
SizedBox(height: 100.0, width: double.infinity),
Align(
alignment: Alignment(0.8, -1.0),
heightFactor: 0.5,
child: FloatingActionButton(
onPressed: null,
child: Icon(Icons.add),
),
)
],
),
);
}
}
Correct solution for anchor FAB.
Another solution using stack and container. FAB's place is based on its sibling Container widget's size and clicks/taps work properly.
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: MyWidget(),
),
);
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(bottom: 28),
child: Container(
width: double.infinity,
height: 150,
color: Color.fromRGBO(55, 55, 55, 0.2),
padding: EdgeInsets.all(15),
child: Text(
'Any container with bottom padding with half size of the FAB'),
),
),
Positioned(
bottom: 0,
right: 10,
child: FloatingActionButton(
child: Icon(
Icons.play_arrow,
size: 40,
),
onPressed: () => print('Button pressed!'),
),
),
],
),
);
}
}
CodePan link for anchor FAB
The correct solution is to use a "Stack" and "Positioned" widged like:
return Stack(
children: <Widget>[
Card(
color: Color(0xFF1D3241),
margin: EdgeInsets.only(bottom: 40), // margin bottom to allow place the button
child: Column(children: <Widget>[
...
],
),
Positioned(
bottom: 0,
right: 17,
width: 80,
height: 80,
child: FloatingActionButton(
backgroundColor: Color(0xFFF2638E),
child: Icon(Icons.play_arrow,size: 70,)
),
),
],
);

Side Radial Menu in flutter

Please how to create Side Radial Menu in flutter like a picture and make rolling when user tap in it
Any help would be appreciated.
This can be achieved by using a GestureDetector, Transform, trigonometry and some clipping with ClipRect.
Using GestureDetector, it is possible to see the drag distance that a user inputs. This can be used to determine how much to rotate the widgets.
Using Transform, it is possible to move widgets to specific locations.
Trigonometry is used to determine the position of the widgets to the centre of the circle.
Using ClipRect, it is possible to clip out the left side of the widgets.
It is possible to reverse scroll direction by instead taking the distance of the drag be turned negative.
Here is the code to make a rotating menu that uses a custom widget that I have recently created for answering this question(Add more Widgets to the Widget list if you want):
import 'dart:math' as math;
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body:CircularScrollView(//wrap this with align if you want it to be aligned to the right of the screen
[//add more widgets or remove as you'd like
GestureDetector(
onTap: (){},//insert function when icon is tapped
child: Container(
child: Center(child: Text('a')),
height: 20,
width: 20,
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
),
),
GestureDetector(
onTap: (){},//insert function when icon is tapped
child: Container(
child: Center(child: Text('b')),
height: 20,
width: 20,
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
),
),
GestureDetector(
onTap: (){},//insert function when icon is tapped
child: Container(
child: Center(child: Text('c')),
height: 20,
width: 20,
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
),
),
GestureDetector(
onTap: (){},//insert function when icon is tapped
child: Container(
child: Center(child: Text('d')),
height: 20,
width: 20,
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
),
),
GestureDetector(
onTap: (){},//insert function when icon is tapped
child: Container(
child: Center(child: Text('e')),
height: 20,
width: 20,
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
),
),
],
radius: 100,
padding: 0,//add double the radius entered to clip out the right side
itemMaxHeight: 20,//effects clipping border height
itemMaxWidth: 20,//effects clipping border width
),
),
);
}
}
class CircularScrollView extends StatefulWidget {
final List<Widget> items;
final double radius;
final double itemMaxHeight;
final double itemMaxWidth;
final double padding;
final bool reverse;
CircularScrollView(this.items, {Key key, this.radius=10, this.itemMaxHeight=0, this.itemMaxWidth=0, this.padding=0, this.reverse=false}) : super(key: key);
#override
_CircularScrollViewState createState() => _CircularScrollViewState();
}
class _CircularScrollViewState extends State<CircularScrollView> {
double lastPosition;
List<Widget> transformItems= [];
double degreesRotated = 0;
#override
void initState() {
setState(() {
_calculateTransformItems();
});
super.initState();
}
void _calculateTransformItems(){
transformItems= [];
for(int i = 0; i<widget.items.length; i++){
double startAngle = (i/widget.items.length)*2*math.pi;
double currentAngle = degreesRotated+startAngle;
transformItems.add(
Transform(
transform: Matrix4.identity()..translate(
(widget.radius)*math.cos(currentAngle),
(widget.radius)*math.sin(currentAngle),
),
child: widget.items[i],
),
);
}
}
void _calculateScroll(DragUpdateDetails details){
if (lastPosition == null){
lastPosition = details.localPosition.dy;
return;
}
double distance = details.localPosition.dy - lastPosition;
double distanceWithReversal = widget.reverse?-distance:distance;
lastPosition =details.localPosition.dy;
degreesRotated += distanceWithReversal/(widget.radius);
_calculateTransformItems();
}
#override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.centerLeft,
child: Container(
height: widget.radius*2+widget.itemMaxHeight,
width: widget.radius*2 + widget.itemMaxWidth,
child: GestureDetector(
onVerticalDragUpdate: (details)=>setState((){_calculateScroll(details);}),
onVerticalDragEnd: (details){lastPosition=null;},
child: Container(
height: double.infinity,
width: double.infinity,
color: Colors.transparent,
child: ClipRect(
child: Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.only(left: widget.padding),
child: Stack(
children: transformItems,
),
),
),
),
),
),
),
);
}
}
When using this code, do not modify the insides of the custom widget unless you know exactly what that section of the code does. When aligning the widget, please instead wrap the custom widget from the outside.
You can try using this package, circle_wheel_scroll, move around this widget inside Stack, place with Positioned with negative left position if necessary.
CircleListScrollView(
physics: CircleFixedExtentScrollPhysics(),
axis: Axis.horizontal,
itemExtent: 80,
children: List.generate(20, _buildItem),
radius: MediaQuery.of(context).size.width * 0.6,
),
or this listwheelscrollview
ListWheelScrollView(
itemExtent: 100,
// diameterRatio: 1.6,
// offAxisFraction: -0.4,
// squeeze: 0.8,
clipToSize: true,
children: <Widget>[
RaisedButton(onPressed:null ,
child: Text("Item 1",textAlign:TextAlign.start,
style:TextStyle(color:Colors.black,fontWeight: FontWeight.bold,fontSize: 25),),) ,
RaisedButton(onPressed:null ,
child: Text("Item 2",textAlign:TextAlign.center,
style:TextStyle(color:Colors.black,fontWeight: FontWeight.bold,fontSize: 25),),) ,
RaisedButton(onPressed:null ,
child: Text("Item 3",textAlign:TextAlign.center,
style:TextStyle(color:Colors.black,fontWeight: FontWeight.bold,fontSize: 25),),) ,
RaisedButton(onPressed:null ,
child: Text("Item 4",textAlign:TextAlign.center,
style:TextStyle(color:Colors.black,fontWeight: FontWeight.bold,fontSize: 25),),) ,
RaisedButton(onPressed:null ,
child: Text("Item 5",textAlign:TextAlign.center,
style:TextStyle(color:Colors.black,fontWeight: FontWeight.bold,fontSize: 25),),) ,
RaisedButton(onPressed:null ,
child: Text("Item 6",textAlign:TextAlign.center,
style:TextStyle(color:Colors.black,fontWeight: FontWeight.bold,fontSize: 25),),) ,
RaisedButton(onPressed:null ,
child: Text("Item 7",textAlign:TextAlign.center,
style:TextStyle(color:Colors.black,fontWeight: FontWeight.bold,fontSize: 25),),) ,
RaisedButton(onPressed:null ,
child: Text("Item 8",textAlign:TextAlign.center,
style:TextStyle(color:Colors.black,fontWeight: FontWeight.bold,fontSize: 25),),) ,
],
),

Fading Edge ListView - Flutter

has anyone come across something like fadingEdgeLength in Android for Flutter so that when you scroll up items start fading into the top of the screen?
Below is my interface built up of the Widgets.
If it helps these are the properties I'm referring to:
android:fadingEdgeLength="10dp"
android:requiresFadingEdge="horizontal">
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('CMS Users'),
),
body: ListView.builder(
padding: EdgeInsets.only(top: 20.0, left: 4.0),
itemExtent: 70.0,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 10.0,
child: InkWell(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new PeopleDetails("Profile Page", profiles[index]),
));
},
child: ListTile(
leading: CircleAvatar(
child: Text(profiles[index].getInitials()),
backgroundColor: Colors.deepPurple,
radius: 30.0,
),
title: Text(
data[index]["firstname"] + "." + data[index]["lastname"]),
subtitle: Text(
data[index]["email"] + "\n" + data[index]["phonenumber"]),
),
),
);
}),
);
}
}
As others have mentioned, you can put the ListView under a ShaderMask, but with minor extra parameterizations you can get much better results - at least if you want to achieve what I wanted.
Optionally you can set the [stops] list for the LinearGradient:
The [stops] list, if specified, must have the same length as [colors]. It specifies fractions of the vector from start to end, between 0.0 and 1.0, for each color.
Plus: There are blend modes, where the color channels of the source are ignored, only the opacity has an effect. BlendMode.dstOut is also such in the example below. As you can see in the screenshot, the purple color is not used concretely, only for the fractions of the vector.
You can play with the different [blendMode] settings, there are quite a few of them.
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: FadingListViewWidget(),
),
),
);
}
class FadingListViewWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
height: 320,
child: ShaderMask(
shaderCallback: (Rect rect) {
return LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.purple, Colors.transparent, Colors.transparent, Colors.purple],
stops: [0.0, 0.1, 0.9, 1.0], // 10% purple, 80% transparent, 10% purple
).createShader(rect);
},
blendMode: BlendMode.dstOut,
child: ListView.builder(
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
return Card(
color: Colors.orangeAccent,
child: ListTile(
title: Text('test test test test test test'),
),
);
},
),
),
),
);
}
}
You could apply a ShaderMask on top of ListView and use BlendMode to get what you want.
Widget animationsList() {
return Expanded(
child: ShaderMask(
shaderCallback: (Rect bounds) {
return LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: <Color>[Colors.transparent,Colors.red],
).createShader(bounds);
},
child: Container(height: 200.0, width: 200.0, color: Colors.blue,),
blendMode: BlendMode.dstATop,
),
);
I had similar request so I created a library for this task.
You can find it here: fading_edge_scrollview
To use it you need to add a ScrollController to your ListView and then pass this ListView as child to FadingEdgeScrollView.fromScrollView constructor
Wrap the Listview with Stack, add the Listview as the first child, the second is Positioned Container with LinearGradient.
Sample from my code:
Stack:
return Stack(
children: <Widget>[
ListView(
scrollDirection: Axis.horizontal,
children: _myListOrderByDate,
),
FadeEndListview(),
],
);
The overlay class:
class FadeEndListview extends StatelessWidget {
const FadeEndListview({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Positioned(
right: 0,
width: 8.0,
height: kYoutubeThumbnailsHeight,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerRight,
end: Alignment.centerLeft,
stops: [0.0, 1.0],
colors: [
Theme.of(context).scaffoldBackgroundColor,
Theme.of(context).scaffoldBackgroundColor.withOpacity(0.0),
],
),
),
),
);
}
}
And it will look something like this:
Try to use
Text(
'This is big text, I am using Flutter and trying to fade text',
overflow: TextOverflow.fade,
maxLines: 1,
),

Resources