How can I resize CircularProgressIndicator in flutter? - dart

I saw this question and this issue, but it couldn't solve my problem. I tried SizedBox and SizedBox.fromSize and also BoxConstraints, but all of them didn't work.
How can I handle it?
import 'package:flutter/material.dart';
import 'package:mymovie/bloc_helpers/bloc_event_state_builder.dart';
import 'package:mymovie/logics/intro/intro.dart';
import 'package:mymovie/resources/strings.dart';
import 'package:mymovie/utils/bloc_navigator.dart';
import 'package:mymovie/utils/bloc_snackbar.dart';
import 'package:mymovie/utils/service_locator.dart';
class IntroScreen extends StatefulWidget{
#override
_IntroScreenState createState() => _IntroScreenState();
}
class _IntroScreenState extends State<IntroScreen> with SingleTickerProviderStateMixin{
final IntroBloc introBloc = sl.get<IntroBloc>();
AnimationController animationController;
Animation buttonSqueeze;
#override
void initState() {
super.initState();
animationController = AnimationController(
duration: const Duration(milliseconds: 1500),
vsync: this
);
buttonSqueeze = Tween(
begin: 320.0,
end: 70.0
).animate(CurvedAnimation(
parent: animationController,
curve: Interval(0.0,0.250)
));
animationController.addListener(() {
if(animationController.isCompleted) {
introBloc.emitEvent(IntroEventKakaoLogin());
}
});
}
Future<void> _playAnimation() async{
try {
await animationController.forward();
} on TickerCanceled {}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: double.infinity,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/ironman.jpg'),
fit: BoxFit.cover,
colorFilter: ColorFilter.mode(Colors.black.withOpacity(0.6), BlendMode.darken)
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.only(top: 180.0),
child: Text(
'영화일기',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 70.0
),
),
),
SizedBox(height: 20.0),
Container(
color: Colors.white,
width: 200.0,
height: 4.0,
),
SizedBox(height: 200.0),
AnimatedBuilder(
animation: buttonSqueeze,
builder: (_,__){
return BlocBuilder(
bloc: introBloc,
builder: (context, IntroState state){
if(state.isKakaoLoginSucceeded) {
BlocNavigator.pushReplacementNamed(context, routeHome);
}
if(state.isKakaoLoginFailed) {
BlocSnackbar.show(context, '로그인에 실패하였습니다.');
introBloc.emitEvent(IntroEventStateClear());
}
return GestureDetector(
child: Container(
width: buttonSqueeze.value,
height: 60.0,
decoration: BoxDecoration(
color: Colors.yellow,
borderRadius: BorderRadius.circular(15.0)
),
child: buttonSqueeze.value>75.0 ? Row(
children: <Widget>[
SizedBox(width: 20.0),
buttonSqueeze.value<100.0 ? Container() :
Image.asset('assets/images/kakao.png'),
buttonSqueeze.value<300.0 ? Container() :
Container(
child: Text(
'카카오톡으로 로그인',
style: TextStyle(
color: Colors.brown,
fontWeight: FontWeight.bold,
fontSize: 20.0
),
),
)
],
) :
SizedBox(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.brown),
strokeWidth: 1.0,
),
width: 30.0,
height: 30.0,
)
),
onTap: () => _playAnimation()
);
}
);
}
)
],
)
)
);
}
}

Try this way, this solved my problem:
new Container(
height: 60.0,
child: new Center(child: new CircularProgressIndicator()),
)

Related

Unable to verify phone number and code correctly

first of all, i do apologise if i am not describing the problem as thorough or as easy to understand as possible, forgive me as i just started learning how to build flutter chat app. i have the code below and i have integrated with firebase. i also enabled phone sign-in method and have input phone number for testing. what i am facing is that my app is able to bypass the registration screen and verification screen even though i have provided the wrong phone number and verification code. i have attached my code below and do appreciate all the help i can get.
// ignore_for_file: deprecated_member_use
import 'package:country_pickers/country.dart';
import 'package:country_pickers/country_pickers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:influential_brands_club/colors.dart';
import 'package:influential_brands_club/presentation/bloc/auth/auth_cubit.dart';
import 'package:influential_brands_club/presentation/bloc/phone_auth/phone_auth_cubit.dart';
import 'package:influential_brands_club/presentation/pages/phone_verification_page.dart';
import 'package:influential_brands_club/presentation/pages/set_initial_profile_page.dart';
import 'package:influential_brands_club/presentation/screens/home_screen.dart';
import 'package:influential_brands_club/presentation/widgets/theme/style.dart';
class RegistrationScreen extends StatefulWidget {
const RegistrationScreen({Key? key}) : super(key: key);
#override
State<RegistrationScreen> createState() => _RegistrationScreenState();
}
class _RegistrationScreenState extends State<RegistrationScreen> {
static Country _selectedFilteredDialogCountry =
CountryPickerUtils.getCountryByPhoneCode("65");
String _countryCode = _selectedFilteredDialogCountry.phoneCode;
String _phoneNumber = "";
final TextEditingController _phoneAuthController = TextEditingController();
#override
void dispose() {
_phoneAuthController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: BlocConsumer<PhoneAuthCubit, PhoneAuthState>(
listener: (context, phoneAuthState) {
if (phoneAuthState is PhoneAuthSuccess) {
BlocProvider.of<AuthCubit>(context).loggedIn();
}
if (phoneAuthState is PhoneAuthFailure) {
Scaffold.of(context).showSnackBar(SnackBar(
backgroundColor: Colors.red,
content: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text("Invalid Code"),
Icon(Icons.error_outline)
],
),
),
));
}
}, builder: (context, phoneAuthState) {
if (phoneAuthState is PhoneAuthSmsCodeReceived) {
return PhoneVerificationPage(
phoneNumber: _phoneNumber,
);
}
if (phoneAuthState is PhoneAuthProfileInfo) {
return SetInitialProfileWidget(phoneNumber: _phoneNumber);
}
if (phoneAuthState is PhoneAuthLoading) {
return const Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
if (phoneAuthState is PhoneAuthSuccess) {
return BlocBuilder<AuthCubit, AuthState>(
builder: (context, authState) {
if (authState is Authenticated) {
return HomeScreen(
uid: authState.uid,
);
}
return Container();
});
}
return _bodyWidget();
}),
);
}
Widget _bodyWidget() {
return Scaffold(
backgroundColor: Colors.black,
body: Container(
margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 60),
child: Column(children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const <Widget>[
Text(""),
Text("Verify your phone number",
style: TextStyle(
fontSize: 18,
color: yellowColor,
fontWeight: FontWeight.w500)),
Icon(
Icons.more_vert,
color: Colors.white,
)
],
),
const SizedBox(
height: 30,
),
const Text(
"IB Club will send an SMS message (carrier charges may apply) to verify your phone number. Enter your country code and phone number below:",
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
),
const SizedBox(
height: 30,
),
ListTile(
tileColor: primaryColor,
onTap: _openFilteredCountryPickerDialog,
title: _buildDialogItem(_selectedFilteredDialogCountry),
),
const SizedBox(
height: 8,
),
Row(
children: <Widget>[
Container(
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
width: 1.5,
color: yellowColor,
))),
width: 80,
height: 42,
alignment: Alignment.center,
child: Text(_selectedFilteredDialogCountry.phoneCode,
style: const TextStyle(color: Colors.white)),
),
const SizedBox(
width: 12,
),
Expanded(
child: SizedBox(
height: 40,
child: TextField(
controller: _phoneAuthController,
decoration: const InputDecoration(
hintText: "Phone Number",
hintStyle: TextStyle(color: Colors.white54),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: darkPrimaryColor),
)),
cursorColor: Colors.white,
style: const TextStyle(color: Colors.white)),
),
),
],
),
const SizedBox(
width: 8,
),
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: MaterialButton(
color: yellowColor,
onPressed: _submitVerifyPhoneNumber,
child: const Text(
"Next",
style: TextStyle(
fontSize: 18,
color: Colors.black,
),
),
),
),
)
])));
}
void _openFilteredCountryPickerDialog() {
showDialog(
context: context,
builder: (_) => Theme(
data: Theme.of(context).copyWith(
primaryColor: primaryColor,
),
child: CountryPickerDialog(
titlePadding: const EdgeInsets.all(8.0),
searchCursorColor: Colors.black,
searchInputDecoration: const InputDecoration(
hintText: "Search",
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: darkPrimaryColor),
)),
isSearchable: true,
title: const Text("Select your phone code",
style: TextStyle(color: yellowColor)),
onValuePicked: (Country country) {
setState(() {
_selectedFilteredDialogCountry = country;
_countryCode = country.phoneCode;
});
},
itemBuilder: _buildDialogItem,
),
));
}
Widget _buildDialogItem(Country country) {
return Container(
height: 40,
alignment: Alignment.center,
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(color: primaryBlack, width: 1),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
CountryPickerUtils.getDefaultFlagImage(country),
const SizedBox(
height: 8.0,
),
Text(" +${country.phoneCode} "),
const SizedBox(
height: 8.0,
),
SizedBox(width: 155, child: Text(country.name)),
const Spacer(),
const Icon(Icons.arrow_drop_down)
],
),
);
}
void _submitVerifyPhoneNumber() {
if (_phoneAuthController.text.isNotEmpty) {
_phoneNumber = "+$_countryCode${_phoneAuthController.text}";
BlocProvider.of<PhoneAuthCubit>(context).submitVerifyPhoneNumber(
phoneNumber: _phoneNumber,
);
}
}
}

Flutter - Custom sliver app bar with search bar

I want to have a custom sliver appBar with a search bar in it. I made a normal app bar that looks like this : But I want that when we scroll down, the app bar looks like that :
Actually, the code of the normal app bar is just a green AppBar of elevation: 0 and just below I add my Header(). Here's the code of my Header :
class Header extends StatefulWidget {
String title;
IconData icon;
Header({#required this.title, #required this.icon});
#override
_HeaderState createState() => _HeaderState();
}
class _HeaderState extends State<Header> {
TextEditingController _editingController;
#override
void initState() {
super.initState();
_editingController = TextEditingController();
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return PreferredSize(
preferredSize: size,
child: Container(
margin: EdgeInsets.only(bottom: kDefaultPadding * 2.5),
height: size.height*0.2,
child: Stack(
children: [
Container(
height: size.height*0.2-27,
width: size.width,
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(36),
bottomRight: Radius.circular(36),
)
),
child: Align(
alignment: Alignment.topCenter,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(widget.title, style: Theme.of(context).textTheme.headline4.copyWith(color: Colors.white, fontWeight: FontWeight.bold)),
SizedBox(width: 20,),
Icon(widget.icon, size: 40, color: Colors.white,)
],
)),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
alignment: Alignment.center,
margin: EdgeInsets.symmetric(horizontal: kDefaultPadding),
padding: EdgeInsets.symmetric(horizontal: kDefaultPadding),
height: 54,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [BoxShadow(
offset: Offset(0, 10),
blurRadius: 50,
color: Theme.of(context).primaryColor.withOpacity(0.23),
)]
),
child: Row(
children: [
Expanded(
child: TextField(
controller: _editingController,
textAlignVertical: TextAlignVertical.center,
onChanged: (_) => setState(() {}),
decoration: InputDecoration(
hintText: 'Search',
hintStyle: TextStyle(color: Theme.of(context).primaryColor.withOpacity(0.5)),
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
),
),
),
_editingController.text.trim().isEmpty ? IconButton(
icon: Icon(Icons.search, color: Theme.of(context).primaryColor.withOpacity(0.5)),
onPressed: null) :
IconButton(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
icon: Icon(Icons.clear, color: Theme.of(context).primaryColor.withOpacity(0.5)),
onPressed: () => setState(() {
_editingController.clear();
})),
],
),
),
)
],
),
),
);
}
#override
void dispose() {
_editingController.dispose();
super.dispose();
}
}
Any help to build this is welcome.
I've made a simple example to show the main logic.
Create your own SliverPersistentHeaderDelegate and calculate shrinkFactor.
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white70,
body: CustomScrollView(
slivers: [
SliverPersistentHeader(
pinned: true,
floating: false,
delegate: SearchHeader(
icon: Icons.terrain,
title: 'Trees',
search: _Search(),
),
),
SliverFillRemaining(
hasScrollBody: true,
child: ListView(
physics: NeverScrollableScrollPhysics(),
children: [
Text('some text'),
Placeholder(
color: Colors.red,
fallbackHeight: 200,
),
Container(
color: Colors.blueGrey,
height: 500,
)
],
),
)
],
),
);
}
}
class _Search extends StatefulWidget {
_Search({Key key}) : super(key: key);
#override
__SearchState createState() => __SearchState();
}
class __SearchState extends State<_Search> {
TextEditingController _editingController;
#override
void initState() {
super.initState();
_editingController = TextEditingController();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 20, right: 5),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: TextField(
controller: _editingController,
// textAlignVertical: TextAlignVertical.center,
onChanged: (_) => setState(() {}),
decoration: InputDecoration(
hintText: 'Search',
hintStyle: TextStyle(
color: Theme.of(context).primaryColor.withOpacity(0.5)),
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
),
),
),
_editingController.text.trim().isEmpty
? IconButton(
icon: Icon(Icons.search,
color: Theme.of(context).primaryColor.withOpacity(0.5)),
onPressed: null)
: IconButton(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
icon: Icon(Icons.clear,
color: Theme.of(context).primaryColor.withOpacity(0.5)),
onPressed: () => setState(
() {
_editingController.clear();
},
),
),
],
),
);
}
}
class SearchHeader extends SliverPersistentHeaderDelegate {
final double minTopBarHeight = 100;
final double maxTopBarHeight = 200;
final String title;
final IconData icon;
final Widget search;
SearchHeader({
#required this.title,
this.icon,
this.search,
});
#override
Widget build(
BuildContext context,
double shrinkOffset,
bool overlapsContent,
) {
var shrinkFactor = min(1, shrinkOffset / (maxExtent - minExtent));
var topBar = Positioned(
top: 0,
left: 0,
right: 0,
child: Container(
alignment: Alignment.center,
height:
max(maxTopBarHeight * (1 - shrinkFactor * 1.45), minTopBarHeight),
width: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(title,
style: Theme.of(context).textTheme.headline4.copyWith(
color: Colors.white, fontWeight: FontWeight.bold)),
SizedBox(
width: 20,
),
Icon(
icon,
size: 40,
color: Colors.white,
)
],
),
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(36),
bottomRight: Radius.circular(36),
)),
),
);
return Container(
height: max(maxExtent - shrinkOffset, minExtent),
child: Stack(
fit: StackFit.loose,
children: [
if (shrinkFactor <= 0.5) topBar,
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.only(
bottom: 10,
),
child: Container(
alignment: Alignment.center,
child: search,
width: 200,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.white,
boxShadow: [
BoxShadow(
offset: Offset(0, 10),
blurRadius: 10,
color: Colors.green.withOpacity(0.23),
)
]),
),
),
),
if (shrinkFactor > 0.5) topBar,
],
),
);
}
#override
double get maxExtent => 230;
#override
double get minExtent => 100;
#override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
}

Flutter app crashes very often after populating it with data and no errors are showed, just lost connection to device

I have a flutter app that is complex enough and i have been developing it for a while.
the problem is after finishing up with the design code , i started implementing API's to receive actual data and populate the app with it. the app is now crashing quite a lot ( although a little less in release mode).
I am thinking it might be because the android device runs out of memory because of all the complex widgets I display in the app.
I have build all of my widgets Stateful I don't know if that could be a related factor (I am a beginner with flutter programming).
Please I have spent a lot of time in developing this app and it's my first enterprise level flutter app.
I haven't had experience with flutter before and I knew this kind of problems would arise and have no solution I would have gone with Java and Swift to develop the app.
Any help is appreciated guys. Thanks.
the app only displays about a 30-40 images, I don't know where all the data coming from.
Here is the code :
import 'package:flutter/material.dart';
import 'package:bestiee/componenets/constants.dart';
import 'package:bestiee/componenets/cards/single-item-hot-screen-card.dart';
import 'package:bestiee/componenets/buttons/small-round-more-button.dart';
import 'package:bestiee/componenets/cards/single-place-hot-screen-card.dart';
import 'package:bestiee/componenets/cards/single-person-hot-screen-card.dart';
import 'package:bestiee/componenets/cards/single-place-large-hot-screen-card.dart';
import 'package:bestiee/screens/hotScreenSingleScreens/more-hot-items-screen.dart';
import 'package:bestiee/screens/hotScreenSingleScreens/more-hot-places-screen.dart';
import 'package:bestiee/screens/hotScreenSingleScreens/more-hot-people-screen.dart';
import 'package:bestiee/translations.dart';
import 'package:bestiee/models/models.dart';
import 'package:bestiee/networking.dart';
import 'package:bestiee/constants.dart';
import 'dart:convert';
import 'package:http/http.dart';
class HotScreen extends StatefulWidget {
static List<Item> items = [];
static List<Place> places = [];
static List<Person> people = [];
static bool isFirstRun = true;
#override
_HotScreenState createState() => _HotScreenState();
}
class _HotScreenState extends State<HotScreen> {
String getTranslation(String text) {
try {
String translation = Translations.of(context).text(text);
return translation;
} catch (ex) {
print(ex);
return '';
}
}
getAllPlaces() async {
HotScreen.places.removeRange(0, HotScreen.places.length);
Response response = await getRequest(devBaseURL + plainPlaceAPI);
var allPlacesMap = jsonDecode(response.body);
print(allPlacesMap.length);
for (int i = 0; i < allPlacesMap.length; i++) {
var json = allPlacesMap[i];
Place place = Place.fromJson(json);
setState(() {
HotScreen.places.add(place);
});
}
}
getAllItems() async {
HotScreen.items.removeRange(0, HotScreen.items.length);
Response response = await getRequest(devBaseURL + plainItemAPI);
var allItemsMap = jsonDecode(response.body);
for (int i = 0; i < allItemsMap.length; i++) {
var json = allItemsMap[i];
Item item = Item.fromJson(json);
setState(() {
HotScreen.items.add(item);
});
}
}
getAllPeople() async {
HotScreen.people.removeRange(0, HotScreen.people.length);
Response response = await getRequest(devBaseURL + plainPersonAPI);
var allPeopleMap = jsonDecode(response.body);
for (int i = 0; i < allPeopleMap.length; i++) {
var json = allPeopleMap[i];
Person person = Person.fromJson(json);
setState(() {
HotScreen.people.add(person);
});
}
}
#override
void initState() {
super.initState();
if(HotScreen.isFirstRun == true){
getAllItems();
getAllPlaces();
getAllPeople();
HotScreen.isFirstRun = false;
}
}
#override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return Scaffold(
body: Container(
decoration: kPageMainBackgroundColorBoxDecoration,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
//main screen scrollable widgets
child: ListView(
shrinkWrap: true,
children: <Widget>[
Text(
getTranslation('Bestiee'),
style: kBazarGalleryTitleStyle,
),
SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Text('Featured Items', style: kFeatureTitleTextStyle),
),
Container(
height: 700 / 3.5,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: HotScreen.items.length,
itemBuilder: (contet, int index) {
return SingleItemCard(
item: HotScreen.items[index],
isPersonItem: false,
moduleName: HotScreen.items[index].moduleName,
);
}),
),
SizedBox(
height: 10,
),
//more button
Align(
alignment: Alignment.topLeft,
child: Container(
width: 80,
height: 30,
child: SmallRoundMoreButton(onPressed: () {
Navigator.pushNamed(context, MoreHotItemsScreen.id);
}),
),
),
SizedBox(
height: 20,
),
//second hand section
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Text('Second Hand', style: kFeatureTitleTextStyle),
),
// Container(
// height: 700 / 3.5,
// child: ListView.builder(
// scrollDirection: Axis.horizontal,
// shrinkWrap: true,
// itemCount: 9,
// itemBuilder: (contet, int index) {
// return SingleItemCard();
// }),
// ),
SizedBox(
height: 10,
),
Align(
alignment: Alignment.topLeft,
child: Container(
width: 80,
height: 30,
child: SmallRoundMoreButton(
onPressed: () {
Navigator.pushNamed(context, MoreHotItemsScreen.id);
},
),
),
),
SizedBox(
height: 30,
),
//places section
Text(
'Featured Plces',
style: kFeatureTitleTextStyle,
),
Container(
height: 140,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: HotScreen.places.length,
itemBuilder: (context, int index) {
return Container(
width: 190,
height: 100,
child: SinglePlaceCard(
place: HotScreen.places[index],
));
},
),
),
//
Align(
alignment: Alignment.topLeft,
child: Container(
width: 80,
height: 30,
child: SmallRoundMoreButton(
onPressed: () {
Navigator.pushNamed(context, MoreHotPlacesScreen.id);
},
),
),
),
SizedBox(
height: 30,
),
//people section
Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: Text(
'People',
style: kFeatureTitleTextStyle,
),
),
Container(
height: 120,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: HotScreen.people.length,
itemBuilder: (context, int index) {
return Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: SinglePersonHotScreenCard(
person: HotScreen.people[index],
),
),
);
},
),
),
Align(
alignment: Alignment.topLeft,
child: Container(
width: 80,
height: 30,
child: SmallRoundMoreButton(
onPressed: () {
Navigator.pushNamed(context, MoreHotPeopleScreen.id);
},
),
),
),
SizedBox(
height: 60,
),
//single shops section
Container(
height: 100.0 * 3,
child: Column(
children: List.generate(5, (index) {
return Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: SinglePlaceLargeHotCard(place: HotScreen.places[index],)
),
);
}),
)
),
],
),
),
),
),
);
}
}
code for SingleItemCard :
class SingleItemCard extends StatelessWidget {
SingleItemCard({
this.cardHeight = 300,
this.cardWidth = 200,
this.color = kAppOrangeColor,
this.isExtraInfoShowen = true,
this.item,
this.isPersonItem,
this.moduleName});
final double cardHeight;
final double cardWidth;
final Color color;
final bool isExtraInfoShowen;
final Item item;
final bool isPersonItem;
final String moduleName;
#override
Widget build(BuildContext context) {
String imageURL ;
//remove the null part in production
if(item.moduleName == 'item' || item.moduleName == null ){
imageURL = imageBaseURLPlaces + item.imageVariants[0].imageURL;
}else if (item.moduleName == 'person' ){
imageURL = imageBaseURLPeople + item.imageVariants[0].imageURL;
print(imageURL);
}
int ratingUserCount = item.ratingUserCount;
return FittedBox(
child: Padding(
padding: const EdgeInsets.only(right: 7),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SingleItemScreen(
item: item,
),
),
);
},
child: Stack(
alignment: Alignment.bottomRight,
children: <Widget>[
//upper item description
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Visibility(
visible: isExtraInfoShowen,
child: CircleRater(
isRatingDisabled: true,
rating: item.rating,
ratingUserCount: item.ratingUserCount != null ? ratingUserCount : 0,
),
),
SizedBox(
width: 150,
child: Text(
// 'Item Name Here no. 1',
item.name,
overflow: TextOverflow.clip,
style: TextStyle(
fontSize: 15,
color: Colors.black,
fontWeight: FontWeight.w500),
softWrap: false,
),
),
//item card
Container(
height: cardHeight,
width: cardWidth,
child: Container(
width: 100,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(10)),
// child: Image.asset(
// 'images/item-image1.jpeg',
// width: 180,
// fit: BoxFit.fill,
// ),
child: CachedNetworkImage(imageUrl: imageURL, fit: BoxFit.fill,)
),
),
),
],
),
//lower price widget
Visibility(
visible: isExtraInfoShowen,
child: Align(
alignment: Alignment.bottomLeft,
child: Container(
width: 100,
height: 20,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(10),
topLeft: Radius.circular(5)),
color: color),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 3, horizontal: 4),
child: Align(
alignment: Alignment.bottomRight,
child: Text(
// '1000000 IQD',
item.priceIQD.toString() + ' IQD',
style: TextStyle(
fontSize: 12,
color: Colors.white,
),
textAlign: TextAlign.start,
),
),
),
),
),
)
],
),
),
),
);
}
}
SinglePlaceCard :
class SinglePlaceCard extends StatelessWidget {
SinglePlaceCard({this.place});
Place place;
#override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
double widgetWidth = screenWidth / 2.3;
int ratingUserCount = place.ratingUserCount;
String imageURL = place.coverImages != null
? imageBaseURLPlaces +
place.coverImages[0].imageURL
: '';
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SinglePlaceScreen(place: place, isScreenCalledFromOwnerSelfRegistrationScreen: false,),
),
);
},
child: FittedBox(
child: Padding(
padding: const EdgeInsets.only(right: 10),
child: Container(
child: Stack(
alignment: Alignment.bottomRight,
children: <Widget>[
Column(
//upper place name and rating
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
CircleRater(
isRatingDisabled: true,
rating: place.rating,
ratingUserCount: place.ratingUserCount != null ? ratingUserCount : 0,
),
SizedBox(
width: widgetWidth,
child: Text(
place.name,
overflow: TextOverflow.clip,
style: TextStyle(
fontSize: 12,
color: Colors.black,
fontWeight: FontWeight.w500),
softWrap: false,
),
),
//place card image
Container(
height: 80,
width: 170,
child: Container(
width: 150,
decoration: BoxDecoration(
color: kAppMainDarkGreenColor,
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(10)),
child: place.coverImages == null
? Image.asset(
'images/blank-placeholder-images/blank-image-placeholder.png',
width: screenWidth / 4,
fit: BoxFit.fill,
)
: CachedNetworkImage(
imageUrl: imageURL,
fit: BoxFit.fill,
),
),
),
),
],
),
//lower tag
Align(
alignment: Alignment.bottomLeft,
child: Container(
width: 100,
height: 20,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(3),
bottomRight: Radius.circular(8)),
color: Colors.black54),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 3, horizontal: 4),
child: Align(
alignment: Alignment.bottomRight,
child: FittedBox(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
EyeIconWithText(
size: 13,
),
Padding(
padding: const EdgeInsets.only(right: 5),
child: Container(
width: 10,
height: 10,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(8),
),
color: place.isOnline != null &&
place.isOnline == true
? Colors.green
: Colors.red),
),
),
Text(
place.isOpen != null
? place.isOpen ? 'Open Now' : 'Colosed Now'
: 'Closed Now',
style: TextStyle(
fontSize: 12,
color: Colors.white,
),
textAlign: TextAlign.start,
),
],
),
),
),
),
),
)
],
),
),
),
),
);
}
}
SinglePersonHotScreenCard :
class SinglePersonHotScreenCard extends StatelessWidget {
SinglePersonHotScreenCard(
{ this.isExtraInfoShowen = false, this.person});
final bool isExtraInfoShowen;
final Person person;
#override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
final ratingPersonCount = person.ratingUserCount;
return Padding(
padding: const EdgeInsets.only(bottom: 10),
child: GestureDetector(
onTap: () {
Navigator.pushNamed(context, SinglePersonScreen.id);
},
child: FittedBox(
child: Column(
children: <Widget>[
//upper label and rating
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
CircleRater(
isRatingDisabled: true,
rating: person.rating,
ratingUserCount: person.ratingUserCount != null ? ratingPersonCount : 0,
),
Text(
person.name,
style: TextStyle(color: Colors.black),
),
],
),
Stack(
alignment: Alignment.center,
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.black54,
borderRadius: BorderRadius.all(Radius.circular(1000)),
),
width: screenWidth / 3.6,
height: screenWidth / 3.6,
),
Visibility(
visible: person != null,
child: CircleAvatar(
radius: 50,
backgroundImage: NetworkImage(imageBaseURLPeople + person.profileImageURL,)
),
),
Visibility(
visible: person == null,
child: ClipOval(
child: SizedBox(
width: screenWidth / 4,
child:
Image.asset('images/blank-placeholder-images/person-placeholder.jpg'),
),
),
),
],
),
Text(
person.jobTitle,
style: TextStyle(color: Colors.black),
),
Padding(
padding: const EdgeInsets.only(top: 2.0),
child: Container(
width: 15,
height: 15,
decoration: kOnlineOfflineIndicatorBoxDecoration,
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Visibility(
visible: this.isExtraInfoShowen,
child: ThumbsUpWithLabel(),
),
)
],
),
),
),
);
}
}
I have ran the devtool, the app uses too much m memory, I am not sure why.
I changed the code there is a lot less crashes. I use this code
getAllPlaces() async {
List<Place> places = widget.places;
places.removeRange(0, places.length);
List<Place> _places = [];
Response response = await getRequest(devBaseURL + plainPlaceAPI);
var allPlacesMap = jsonDecode(response.body);
for (int i = 0; i < allPlacesMap.length; i++) {
var json = allPlacesMap[i];
Place place = Place.fromJson(json);
_places.add(place);
}
setState(() {
places.addAll(_places );
print('all added');
});
}
The app crash seems to be caused by Out Of Memory issue. Checking on the snippets you've provided, memory issues were caused by nested ListViews rendering Widgets that displays images. While the widgets in ListViews are only rendered when near the viewport, multiple ListViews still adds up to the total memory consumed. I suggest trimming down the images displayed and nest ListViews sparingly to prevent these issues.

Scroll controller is not attached to any scroll views

I am attaching scrollController to a listView builder. I am controlling scrolling using Slider.B ut I am getting error "Scroll controller is not attached to any scroll views".If I set max of Slider to some static value error is gone but if i set max = scrollController.position.maxScrollExtent it gives error.
scrollController = ScrollController(initialScrollOffset: 0.0);
scrollController.addListener(scrollListener);
Container(
decoration: BoxDecoration(color: Colors.black),
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: ListView.builder(
controller: scrollController,
scrollDirection: Axis.horizontal,
itemCount: totalSegments,
itemBuilder: (BuildContext context, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: 70.0,
width: 148.0,
margin: EdgeInsets.only(top: 10.0),
decoration: BoxDecoration(
color: Colors.grey[800],
),
child: Row(
children: <Widget>[
Container(
width: 20.0,
decoration: BoxDecoration(color: Colors.grey[900]),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
width: 7.0,
height: 7.0,
decoration:
BoxDecoration(color: Colors.white),
),
Container(
width: 7.0,
height: 7.0,
decoration:
BoxDecoration(color: Colors.white),
),
Container(
width: 7.0,
height: 7.0,
decoration:
BoxDecoration(color: Colors.white),
),
],
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(5.0),
),
margin:
new EdgeInsets.only(top: 1.0, bottom: 1.0),
child: selectedSegment[index] != null
? SizedBox(
height: double.infinity,
width: double.infinity,
child: Center(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: NetworkImage(
selectedSegment[index]
['segmentUrl']),
),
),
)),
)
: Container(),
),
),
],
),
),
Container(
width: 148.0,
height: MediaQuery.of(context).size.height - 130.0,
child: ListView(
scrollDirection: Axis.vertical,
children: buildSegmentList(index),
),
),
],
);
},
),
),
Try this code i got bottom and up event state in listview..
class ScrollViewDemo extends StatelessWidget {
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: ScrollViewTest(),
);
}
}
class ScrollViewTest extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return ScrollViewState();
}
}
class ScrollViewState extends State<ScrollViewTest> {
ScrollController _controller;
String message = "";
_scrollListener() {
if (_controller.offset >= _controller.position.maxScrollExtent &&
!_controller.position.outOfRange) {
setState(() {
message = "reach the bottom";
});
}
if (_controller.offset <= _controller.position.minScrollExtent &&
!_controller.position.outOfRange) {
setState(() {
message = "reach the top";
});
}
}
#override
void initState() {
_controller = ScrollController();
_controller.addListener(_scrollListener);
super.initState();
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("Scrollview Demo"),
),
body: Column(
children: <Widget>[
Container(
height: 50.0,
color: Colors.green,
child: Center(
child: Text(message),
),
),
Expanded(
child: ListView.builder(
controller: _controller,
itemCount: 30,
itemBuilder: (context, index) {
return ListTile(title: Text("Index : $index"));
},
),
),
],
),
);
}
}

how to create a custom popup menu with flutter

I want to create a popup menu when clicking on a button from the appbar .. i want something like this to appear:
is there a way to do this in flutter? a package or something?
I tried, but I've faced some problems with showing subwidget exactly this way. So, here two solutions:
class TestScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> with SingleTickerProviderStateMixin {
AnimationController animationController;
bool _menuShown = false;
#override
void initState() {
animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 500));
super.initState();
}
#override
Widget build(BuildContext context) {
Animation opacityAnimation = Tween(begin: 0.0, end: 1.0).animate(animationController);
if (_menuShown)
animationController.forward();
else
animationController.reverse();
return Scaffold(
appBar: AppBar(
actions: <Widget>[IconButton(icon: Icon(Icons.menu), onPressed: (){
setState(() {
_menuShown = !_menuShown;
});
})],
),
body: Stack(
overflow: Overflow.visible,
children: <Widget>[
Positioned(
child: FadeTransition(
opacity: opacityAnimation,
child: _ShapedWidget(),
),
right: 4.0,
top: 16.0,
),
],
),
);
}
}
class _ShapedWidget extends StatelessWidget {
_ShapedWidget();
final double padding = 4.0;
#override
Widget build(BuildContext context) {
return Center(
child: Material(
clipBehavior: Clip.antiAlias,
shape:
_ShapedWidgetBorder(borderRadius: BorderRadius.all(Radius.circular(padding)), padding: padding),
elevation: 4.0,
child: Container(
padding: EdgeInsets.all(padding).copyWith(bottom: padding * 2),
child: SizedBox(width: 150.0, height: 250.0, child: Center(child: Text('ShapedWidget'),),),
)),
);
}
}
class _ShapedWidgetBorder extends RoundedRectangleBorder {
_ShapedWidgetBorder({
#required this.padding,
side = BorderSide.none,
borderRadius = BorderRadius.zero,
}) : super(side: side, borderRadius: borderRadius);
final double padding;
#override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
return Path()
..moveTo(rect.width - 8.0 , rect.top)
..lineTo(rect.width - 20.0, rect.top - 16.0)
..lineTo(rect.width - 32.0, rect.top)
..addRRect(borderRadius
.resolve(textDirection)
.toRRect(Rect.fromLTWH(rect.left, rect.top, rect.width, rect.height - padding)));
}
}
In this case subwidget is below appbar
class TestScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> with SingleTickerProviderStateMixin {
AnimationController animationController;
bool _menuShown = false;
#override
void initState() {
animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 500));
super.initState();
}
#override
Widget build(BuildContext context) {
Animation opacityAnimation = Tween(begin: 0.0, end: 1.0).animate(animationController);
if (_menuShown)
animationController.forward();
else
animationController.reverse();
return Scaffold(
appBar: AppBar(
elevation: 0.0,
actions: <Widget>[Stack(
overflow: Overflow.visible,
children: <Widget>[IconButton(icon: Icon(Icons.menu), onPressed: (){
setState(() {
_menuShown = !_menuShown;
});
}),
Positioned(
child: FadeTransition(
opacity: opacityAnimation,
child: _ShapedWidget(onlyTop: true,),
),
right: 4.0,
top: 48.0,
),
],)],
),
body: Stack(
overflow: Overflow.visible,
children: <Widget>[
Positioned(
child: FadeTransition(
opacity: opacityAnimation,
child: _ShapedWidget(),
),
right: 4.0,
top: -4.0,
),
],
),
);
}
}
class _ShapedWidget extends StatelessWidget {
_ShapedWidget({this.onlyTop = false});
final double padding = 4.0;
final bool onlyTop;
#override
Widget build(BuildContext context) {
return Center(
child: Material(
clipBehavior: Clip.antiAlias,
shape:
_ShapedWidgetBorder(borderRadius: BorderRadius.all(Radius.circular(padding)), padding: padding),
elevation: 4.0,
child: Container(
padding: EdgeInsets.all(padding).copyWith(bottom: padding * 2),
child: onlyTop ? SizedBox(width: 150.0, height: 20.0,) : SizedBox(width: 150.0, height: 250.0, child: Center(child: Text('ShapedWidget'),),),
)),
);
}
}
class _ShapedWidgetBorder extends RoundedRectangleBorder {
_ShapedWidgetBorder({
#required this.padding,
side = BorderSide.none,
borderRadius = BorderRadius.zero,
}) : super(side: side, borderRadius: borderRadius);
final double padding;
#override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
return Path()
..moveTo(rect.width - 8.0 , rect.top)
..lineTo(rect.width - 20.0, rect.top - 16.0)
..lineTo(rect.width - 32.0, rect.top)
..addRRect(borderRadius
.resolve(textDirection)
.toRRect(Rect.fromLTWH(rect.left, rect.top, rect.width, rect.height - padding)));
}
}
In this case top of subwidget is on appbar, but appbar has to have 0.0 elevation
Actually, both of these solutions are not complete in my opinion, but it can help you to find what you need
It might be too late for an answer. But this can be simply achieved by using OverlayEntry widget. We create a widget of that shape and pass it to OverlayEntry widget and then use Overlay.of(context).insert(overlayEntry) to show the overlay and overlayEntry.remove method to remove it.
Here is a medium link to create a Custom DropDown Menu
Hope this helps!
There is a package called flutter_portal which works like Overlay/OverlayEntry but in a declarative way. You can use it for implementing custom tooltips, context menus, or dialogs.
CustomPopupMenu(
pressType: PressType.singleClick,
controller: menu,
arrowColor: AppColor.white,
menuBuilder: () => ClipRect(
clipBehavior: Clip.hardEdge,
child: Container(
height: MediaQuery.of(context).size.height *
ComponentSize.container1height,
width: MediaQuery.of(context).size.width *
ComponentSize.conatiner1width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
ComponentSize.borderradius),
color: AppColor.white,
),
child: ListView.builder(
itemCount: Details.length,
itemBuilder: (context, index) {
return Column(
children: [
InkWell(
onTap: () {
do somthing
},
child: Column(
children: [
Container(
padding: EdgeInsets.only(
left:
ComponentSize.paddingleft),
alignment: Alignment.centerLeft,
child: Text(
Details[index],
style: const TextStyle(
color: Colors.black,
fontFamily: 'Taml_001'),
textAlign: TextAlign.start,
),
),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(
left:
ComponentSize.paddingleft),
child: Text(Details[index],
style: TextStyle(
color: AppColor.black
.withOpacity(
ComponentSize
.opacity1),
fontSize: ComponentSize
.containerfontsize)),
)
],
),
),
const Divider(),
],
);
},
),
)),
child: Container(
color: AppColor.white,
padding: EdgeInsets.only(
top: ComponentSize.paddingbottom,
bottom: ComponentSize.paddingtop,
left: ComponentSize.padding1left),
width: ComponentSize.container2width,
height: ComponentSize.container2height,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: ComponentSize.textcontainerwidth,
height: ComponentSize.textcontainerheight,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Text(
Tamil,
style: const TextStyle(
color: Colors.black,
fontFamily: 'Taml_001'),
),
),
),
SizedBox(
width: ComponentSize.textcontainerwidth,
height: ComponentSize.textcontainerheight,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Text(
English,
style: const TextStyle(
color: Colors.black),
),
),
)
],
),
),
SizedBox(
child: Icon(
Icons.expand_more,
size: ComponentSize.iconarrowsize,
color: Colors.black,
),
)
],
),
),
),

Resources