Flutter size button - android

I'm making a FlatButton for sizes so the user is going to select his own size.
how can I make the button border goes bold when the user presses the button?
-the buttons are created by ListView.builder so I can't set local variables for them.

you can create a variable which hold the button number who's border you want to set bolder and on click you can change value of that variable.
following example clear your idea.
import 'package:flutter/material.dart';
class TextFieldInput extends StatefulWidget {
#override
_TextFieldInputState createState() => _TextFieldInputState();
}
class _TextFieldInputState extends State<TextFieldInput> {
final List<int> list = [1,2,3,4,5,6,7,8,9,0];
int number = -1;
#override
Widget build(BuildContext context) {
return Center(
child: Container(
child: ListView.builder(
itemCount: (list.length).ceil(),
itemBuilder: (context, int index){
return new FlatButton(
key: Key(index.toString()),
child: new Text(list[index].toString()),
shape: Border.all(
width: number==index ? 5.0 : 3.0
),
onPressed: (){
setState(() {
number = index;
});
}
);
}
)
),
);
}
}

Related

ReorderableListView.builder() is not reordering upon user input

My expectation from ReoderableListView.builder() is simply, as what the Flutter doc says, to create a widget that allows users to move/drag list-items up and down the list view. However, what I was getting from my emulator was no dragging animation, no reordering of the list (upon user input), and not even call to the onReorder callback.
Stuff I have tried:
Made sure my taskID and taskName lists have the same length
Added debug outputs for itemBuilder and onReorder callback, surprisingly receiving debug output only from itemBuilder callback
Copied and pasted the widget code and its corresponding lists data exactly to other widget classes (or files) and still got the same result
Added the exactly same ValueKey in the Text() inside the list-view.
Tried using the same list data as what the Text() is rendering, taskNames, for the value ValueKey
The only thing I did not try was directly copying and pasting the official example of this widget to my codebase, but the test code I have should already be very similar to the official example, structurally.
checklist.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'add_task.dart';
class Checklist extends StatefulWidget {
const Checklist({Key? key}) : super(key: key);
#override
State<Checklist> createState() => _ChecklistState();
}
class _ChecklistState extends State<Checklist> {
final List<int> taskID = <int>[0, 1, 2, 4, 6];
final List<String> taskNames = <String>['A', 'B', 'C', 'D', 'E'];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
children: [
const Text("TODO"),
ElevatedButton(
onPressed: () {
},
child: const Text("Google Calendar"),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black12),
),
),
]
),
),
body: ReorderableListView.builder(
itemCount: taskNames.length,
itemBuilder: (BuildContext context, int index) {
print("B");
return ListTile(
key: ValueKey(taskID[index]),
tileColor: Colors.black12,
title: Text('Entry ${taskNames[index]}')
);
},
onReorder: (int oldIndex, int newIndex) {
print("A");
setState(() {
if (newIndex > oldIndex) {
newIndex -= 1;
}
final int elTid = taskID.removeAt(oldIndex);
final String elTnm = taskNames.removeAt(oldIndex);
taskID.insert(newIndex, elTid);
taskNames.insert(newIndex, elTnm);
});
},
),
);
}
}
Your code does work. It moves only on long press and drag. Not on normal drag.. On normal drag it will tend to scroll the list

flutter: how to make a listview update without pressing a button?

so I'm currently working on an application that has a listview on the first screen (implemented on main.dart).
The listview fetches it's data from internet (async).
The problem is that, the listview does not get updated when the data is changed.
(I can implement this functionality simply by designing a 'reload' button and pressing it every time I want the new data. But that's not what I want right now).
In other words, how can I update the listview automatically?
EDIT1: ADDING SOME CODE
code might be messy; see the description at the end.
class RssFeed extends StatelessWidget {
String title;
String pubDate;
RssFeed(this.title, this.pubDate);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Align(
alignment: Alignment.topRight,
child: Text(title),
),
Text(pubDate)
],
),
);
}
}
class FeedsList extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _FeedsListState();
}
}
class _FeedsListState extends State<FeedsList> {
List<Widget> list1 = new List<Widget>();
#override
void initState() {
super.initState();
ls();
}
Future ls() async {
list1.clear();
list.clear();
sites1.clear();
RSS_reader rss_reader = new RSS_reader();
for (var i in saver.list.items) {
sites1.add(
site(siteAdress: i.siteAdress, siteDescription: i.siteDescription));
}
var res = await rss_reader.Get_items(sites1);
for (var val in res) {
list.add(InkWell(
onTap: () => _launchURL(val.item.link),
child: Container(
height: 50,
color: Colors.amber[100],
child: Center(
child: new RssFeed(val.item.title, val.item.pubDate.toString()),
),
)));
}
print(list.length);
setState(() {
list1 = list;
});
}
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: list1.length,
itemBuilder: (BuildContext context, int i) {
return list1[i];
}));
}
}
DESCRIPTION:
As you can guess, this is a RSS reader.
So, I have a class RSSFeed; which makes one of the tiles of Listview.
then in the FeedsList class (stateful widget), I make the listview.
I have a class called RSS_reader and a method Get_items, which gets a bunch of sites as input and puts those sites' newest feeds in a list ('res' in the above code).
Then, I put the items in a list of 'Container's and then build the listview.
Then, in the main function, I create a container like below:
Container(
height: 500,
width: 580,
child: FeedsList(),
)
and there appears the problem; the FeedsList class does not get updated automatically. although if I put a button and navigate to FeedsList class through that button, the list is refreshed and OK.
Thanks for reading and help.
If you just want to fetch data once from your external source use a FutureBuilder, if you want to fetch data multiple times take a look to StreamBuilder. Both widgets will have the behavior you are looking for, with no refresh button.
Simple example of how to use a FutureBuilder:
Future<List<String>> _fetchData() {
return // fetch data from source
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _fetchData,
builder: (BuildContext context, AsyncSnapshot<List<String>> snapshot) {
if (snapshot.hasData && snapshot.data != null) {
// This widget will be built when data is fetched
const List<String> list = snapshot.data;
return ListView(
children: list.map(
(element) => ListTile(
title: Text(element),
),
).asList(),
);
} else {
// This widget will be built while you are waiting for your data to be fetched
return Container(
child: Center(
child: Text("Loading data..."),
),
);
}
},
);
}
You have to stream data and ListView will update automatically.
In the button that you say you can re call your ls() functions, your list should update on tap button
sample:
return Scaffold(
body: ListView.builder(
itemCount: list1.length,
itemBuilder: (BuildContext context, int i) {
return list1[i];
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.refresh),
onPressed: () => ls(),
),
);

Flutter setState executing but not rerendering UI when setting parent stateless widget flag

My app has an introductory feature where it simply informs the user on an action to take, the issue is this help action text (Container(...)) does not get removed one the setState() function is called.
Logical overview of process:
-> `User launches app`
|-> `login`
|-> `show main UI (with help action if first time launch)`
|-> first time launch ? show help text : don't show
| User acknowledges help text, set in preferences
Below are some code snippets of the dart fragments
UiHomePage (main UI - this is the parent UI)
class HomePage extends StatefulWidget {
const HomePage({Key key}) : super(key: key);
#override
_HomePage createState() => _HomePage();
}
class _HomePage extends State<HomePage> {
#override
Widget build(BuildContext context) {
Widget pageDashboardUser() {
...
// Notify UiComponentPartnerSelector if we should show help action text based on AppSharedPreferences().isFirstTap()
Widget middleBrowseCard() {
return new FutureBuilder(
builder: (context, snapshot) {
return UiComponentPartnerSelector(
_displayProfiles, snapshot.data);
},
future: AppSharedPreferences().isFirstTap());
}
var search = topSearch();
var selector = middleBrowseCard();
return Stack(
children: [search, selector],
);
return Scaffold(...)
}
This Widget displays a bunch of profiles with a base card, a text overlay, and a hint text component.
The main focus is showHint define in the constructur (true if the app is launched for the first time), showTapTutorial() which either returns the hint component or an empty container and finally the _onTap(Profile) which handles the onclick event of a card.
UiComponentPartnerSelector (sub UI - the help text is shown here
class UiComponentPartnerSelector extends StatefulWidget {
bool showHint;
final List<Profile> items;
UiComponentPartnerSelector(this.items, this.showHint, {Key key})
: super(key: key);
#override
_UiComponentPartnerSelector createState() => _UiComponentPartnerSelector();
}
class _UiComponentPartnerSelector extends State<UiComponentPartnerSelector> {
UiComponentCard _activeCard;
int _tappedImageIndex = 0;
Widget showTapTutorial() {
if (!widget.showHint) {
return Container();
}
return Container(
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 32),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.6),
borderRadius: BorderRadius.all(Radius.circular(5)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.touch_app,
color: Colors.black.withOpacity(0.6),
),
Text(
"Touch to view partner profile",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black),
)
],
),
);
}
#override
Widget build(BuildContext context) {
Color _standard = Colors.white;
//
// _cache = widget.items.map((e) => {
// e.imageUri.toString(),
// Image.network(e.imageUri.toString())
// });
Future _onTap(Profile e) async {
if (!widget.showHint) {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => UiViewProfile(e)));
} else {
AppSharedPreferences().setFirstTap(false).then((value) {
setState(() {
widget.showHint = false;
});
});
}
}
UiComponentCard createComponentCard(Profile e) {
...
return UiComponentCard(
onTap: () {
_onTap(e);
},
wImage: Center(
child: Image.network(
e.profileImageLink.toString(),
fit: BoxFit.fill,
),
),
wContent:
// Center(
// child: UiTextLine(text: e.displayName),
// ),
Column(
children: [
topBasicInfo(),
Expanded(child: Container()),
showTapTutorial(),
Expanded(child: Container()),
bottomBio()
],
),
);
}
return Container(
child: Stack(...)
);
Problem:
When _onTap(Profile) is clicked and showHint is true.
What should happen:
What SHOULD happen next is AppSharedPreferences().setFirstTap(false) should set the initial tap flag to false, then when finished setState() including setting showHint to false, then rerendering the UI and removing the hint text container (found in showTapTutorial()).
What happens:
What infact happens is when _onTap() is called, it updates the preferences correctly, setState() is called and showHint == false and !widget.showHint in showTapTutorial() is true returning Container() BUT the UI itself doesn't rerender.
Thus after clicking this "button" for the first time, the UI remains (doesn't change). Clicking a second time executes the Navigator.of(context).push(MaterialPageRoute(builder: (context) => UiViewProfile(e))); part WHILE the action help text (tutorial) is still showing. If I click on the same card again
Am I missing something or doing something wrong?

Flutter listview within listview not scrolling

As my first Flutter project I'm building an app for a newspaper. There are a number of news categories. For those categories, I have created a generic Widget, in the home screen that Widget will be shown multiple times for multiple categories in a Listview, those category Widgets have Listview in them too as I bring multiple news from those categories. The Widget class that has this generic Widget is Newsfeed.dart which will be given below.
This generic Widget is called from a another Widget class WidgetFactory.dart which actually calls API and builds the home screen by using the above mentioned generic Widget for categories. This class uses a Listview.builder which is inside FutureBuilder.
The problem is, when I open the app in the screen the news appears but I can't scroll, it stays fixed. I have checked if the API is actually bringing the news, in console I have printed the API response, all of the news are fetched but still I can't scroll.
the flow is main.dart -> WidgetFactory() -> Newsfeed()
WidgetFactory()
class WidgetFactory extends StatefulWidget {
#override
_WidgetFactoryState createState() => _WidgetFactoryState();
}
class _WidgetFactoryState extends State<WidgetFactory> {
List homeScreenCategories = [4, 14, 13, 23, 8015, 22];
Future<List> newsPostList;
List<List<NewsPost>> categoryNewsPostList;
#override
void initState() {
super.initState();
newsPostList = fetchNews();
}
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Container(
alignment: Alignment.center,
child: Container(
child: RefreshIndicator(
child: FutureBuilder(
future: newsPostList,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.data == null) {
return Container(
child: CircularProgressIndicator()
);
} else {
return ListView.builder(
shrinkWrap: true,
physics: const AlwaysScrollableScrollPhysics(),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return _getCategoryNews(snapshot, index);
},
);
}
},
),
onRefresh: () {
fetchNews();
}
),
),
);
}
Future<List> fetchNews() async {
String url = "url";
Response response = await Dio().get(url);
if(response.statusCode == 200) {
List newsPostList = [];
for(int i=0; i<response.data.length; i++) {
newsPostList.add(response.data[i]);
}
return newsPostList;
} else {
throw Exception("Failed to fetch category");
}
}
Widget _getCategoryNews(snapshot, int index) {
List<NewsPost> newsPostList = [];
for(var c in snapshot.data[index]['items']) {
NewsPost newsPost = NewsPost.getNewsPostFromAPI(c);
newsPostList.add(newsPost);
}
return Newsfeed(newsPostList, "National");
}
}
Newsfeed()
class Newsfeed extends StatefulWidget {
String categoryName;
List<NewsPost> newsPostList;
Newsfeed(this.newsPostList, this.categoryName);
#override
_NewsfeedState createState() => _NewsfeedState(this.newsPostList, this.categoryName);
}
class _NewsfeedState extends State<Newsfeed> {
final GlobalKey<ScaffoldState> _scaffoldKeyTwo = new GlobalKey<ScaffoldState>(debugLabel: '_MainScreenKey');
String categoryName;
_NewsfeedState(this.newsPostList, this.categoryName);
List<NewsPost> newsPostList;
var dio = new Dio();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Container(
alignment: Alignment.center,
child: ListView.builder(
shrinkWrap: true,
itemCount: newsPostList.length,
itemBuilder: (BuildContext context, int index) {
print(newsPostList[index]);
return _getNewsPostWidgets(index);
}
),
);
}
Widget _getNewsPostWidgets(int index) {
var newsPost = newsPostList[index];
if(index < 5) {
if(index == 0) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
ScaleTransitionRoute(
page: NewsPostDetails(newsPostList, index)
)
);
},
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(10, 0, 0, 0),
//constraints: BoxConstraints(minWidth: double.infinity, maxWidth: double.infinity),
constraints: BoxConstraints.expand(
width: double.infinity,
height: 40
),
color: const Color(0xFF2b4849),
child: Text(
this.categoryName,
style: TextStyle(
fontSize: 33,
color: Colors.white
),
),
),
BlockHeadline(newsPost)
],
)
);
}
else {
return GestureDetector(
onTap: () {
Navigator.push(
context,
ScaleTransitionRoute(
page: NewsPostDetails(newsPostList, index)
)
);
},
child: ListedNews(newsPost),
);
}
}
else {
return Container(
color: const Color(0xFF2b4849),
child: index == 5 ? FlatButton(
child: Text(
"See More",
style: TextStyle(
color: Colors.white
),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => NewsFeedForSpecificCategory(newsPostList)
)
);
},
) : Container(),
);
}
}
openNewsPostDetails(List<NewsPost> newsPostList, int index) {
Navigator.push(
context,
ScaleTransitionRoute(
page: NewsPostDetails(newsPostList, index)
)
);
}
}
What I have tried
I found some questions that relates to this problem a bit. Tried those.
I used shrinkwrap=true in my Listview.builder, but of no use.
Tried using Column inside SingleChildScrollView(), still did not work.
Inside the Listview.builder added physics as AlwaysScrollable(), also in vain.
As I'm new to flutter what I tried might seem dumb.
One more thing is, the news that shows up in the home screen, that takes me to the details page fine and there swiping left right takes me to other news also. It's the home screen that is causing trouble, not scrolling.
It would be great help if you could kindly give some clues.
I have found the solution to this problem. It was quite simple actually.
In the build() method of my _NewsfeedState class I have added ClampingScrollPhysics() as physics.
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Container(
alignment: Alignment.center,
child: ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
itemCount: newsPostList.length,
itemBuilder: (BuildContext context, int index) {
print(newsPostList[index]);
return _getNewsPostWidgets(index);
}
),
);
}
It worked.
Putting ListView inside ListView is an anti pattern.
There are several solutions for this problem,
Solution 1:
Merge those two list of items into a single list of items and
display it as a single ListView.
Solution 2:
You can use SliverList for your use case. SliverList can wrap multiple SliverLists inside a single CustomScrollView.
This will help you.
child: ListView.builder(
physics: NeverScrollableScrollPhysics(),
Thanks.

ListView displays items twice

I am trying to build a listview in flutter with the following :
The expected functionality is the listview should display 1 item at a time.
class SimpleContentScreen extends StatefulWidget {
#override
_SimpleContentScreenState createState() => _SimpleContentScreenState();
}
class _SimpleContentScreenState extends BaseState<SimpleContentScreen> {
List<SimpleContent> simpleContentList;
List<SimpleContent> displayList = List();
int _currentIndex = 0;
#override
Widget build(BuildContext context) {
simpleContentList = getOOFirstContent();
displayList.add(simpleContentList[_currentIndex]);
return Scaffold(
appBar: buildAppBar("Introduction"),
body: _buildListView(),
floatingActionButton: _buildFab(),
);
}
FloatingActionButton _buildFab() => FloatingActionButton(
onPressed: () {
if( _currentIndex < simpleContentList.length - 1 ) {
setState(() {
_currentIndex = _currentIndex + 1;
displayList.add(simpleContentList[_currentIndex]);
});
}
},
child: Icon(Icons.navigate_next),
foregroundColor: Colors.white,
backgroundColor: Colors.blueGrey,
);
ListView _buildListView() => ListView.builder(
key: Key("_simple_content_list"),
itemCount: displayList.length,
itemBuilder: (context, position) {
return _buildItemView( displayList[position] );
}
);
_buildItemView(SimpleContent displayList) => Container(
padding: const EdgeInsets.all(12),
margin: EdgeInsets.fromLTRB(0, 8, 32, 8),
decoration: BoxDecoration(color: Colors.blueAccent),
child : new Text(
displayList.contentString,
style: buildTextSimpleContent(20))
);
}
Upon press of FAB - it's adding the items twice. Why is this? I have solved it by clearing the displayList and adding all items from 0 to the current index.
I tried setting key to the listview, but that didn't solve it.
Any help or insight appreciated.
setState calls the build method of the Widget to build
So this is what's happening
onPressed method is called when FAB is clicked
_currentIndex = _currentIndex + 1;
displayList.add(simpleContentList[_currentIndex]);
This adds a new item
But then build method is again called
So you again add the element in the list in build method displayList.add(simpleContentList[_currentIndex]);
Solution 1
Remove
simpleContentList = getOOFirstContent();
displayList.add(simpleContentList[_currentIndex]);
from build and add it to initState
Solution 2
delete
displayList.add(simpleContentList[_currentIndex]);
from setState so that the element is added only once
For more details on StateFul Widget Lifecycle method refer here

Categories

Resources