i have an issue with page view, it's working fine for first initialization (i mean when open the screen that contain page view from "Screen A" then go to open the "pageView screen" from other screen called "Screen B") in second time getting this issue
i think this issue happen because the controller re-intialiazed again, but i dispose the controller and make it equal to null when dispose screen
ScrollController attached to multiple scroll views.
'package:flutter/src/widgets/scroll_controller.dart':
package:flutter/…/widgets/scroll_controller.dart:1
Failed assertion: line 109 pos 12: '_positions.length == 1'
Using provider to handle change in tabBar and Page View, the below code of provider class
class PageViewProvider extends BaseViewModel {
// Tabs Controller
int selectedTapIndex = 0;
PageController? pageViewController;
initPageIndex(int index) {
if (pageViewController != null) {
pageViewController = null;
}
print('init index $index');
selectedTapIndex = index;
pageViewController = PageController(initialPage: index, keepPage: false);
}
void changeSelectedTapIndex(int index) {
selectedTapIndex = index;
setState(ViewState.Idle);
}
void changePageView(int index) {
pageViewController!.jumpToPage(index);
}
}
this the tabed item widget with onTap Function to change index of TabBar
Consumer<PageViewProvider>(
builder: (context, pageViewProvider, _) => Container(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: [
Icon(
iconData,
color:
pageViewProvider.selectedTapIndex == selectedIndex
? purpleColor
: grey500,
),
normal14Text(
title,
color:
pageViewProvider.selectedTapIndex == selectedIndex
? purpleColor
: grey500,
),
],
),
).onTap(() {
pageViewProvider.changeSelectedTapIndex(selectedIndex!);
pageViewProvider.changePageView(selectedIndex!);
}));
at least, this is the pageView body
Consumer<PageViewProvider>(
builder: (context, pageViewProvider, _) => PageView(
controller: pageViewProvider.pageViewController,
onPageChanged: (index) {
pageViewProvider.changeSelectedTapIndex(index);
},
pageSnapping: true,
children: [
LeadProfileContent(),
LeadProfileTimeLine(),
LeadProfileCases(),
LeadProfileDeals(),
],
),
),
Thanks in advance.
It's solved. The issue here was with the Consumer above the page view body. Just removed it, and then accessed the pageViewController like this:
context.read<PageViewProvider>.pageViewController
Related
I have a simple app with a CupertinoTabBar. It's almost like shown here: https://codesinsider.com/flutter-cupertino-tabbar/
child: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.home),
label: "Home",
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.person),
label: "Profile",
)
],
),
tabBuilder: (context, index) {
return CupertinoTabView(
builder: (context) {
return data[index];
},
);
},
)
On a Details Page, which is accessible from "Home" and "Profile" there is a Back Button which should lead back to the previous Main page (Profile or Home) (In the Details Page the CupertinoTabBar is not shown) But I'm struggling to achieve this. Any tips would be helpful. (On Android it was easy with defining named routes in the BottomNavigationBar and then just call Navigator.pushNamed)
I need a way to go to page with index 0 or index 1 manually. The CupertinoTabBar should appear again when back is pressed.
Because I had problems with Google Maps and Bitmap descriptor, I tried to preload the icons before loading the Map, like this:
Widget preloadPinsAndLoadSearchMap() {
final config = ImageConfiguration(size: Size(48, 48));
final activePin = 'assets/active-pin.png';
final neutralPin = 'assets/neutral-pin.png';
final home = 'assets/home-map.png';
return FutureBuilder(
future: Future.wait([
BitmapDescriptor.fromAssetImage(config, activePin),
BitmapDescriptor.fromAssetImage(config, neutralPin),
BitmapDescriptor.fromAssetImage(config, home),
]),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return SearchMap(pins: snapshot.data);
} else {
return Container();
}
},
);
}
And the SearchMap and the Markers:
// Each Marker is produced like this:
Marker createMarker(dynamic seller) {
return Marker(
markerId: MarkerId(seller.id),
position: LatLng(seller.latitude, seller.longitude),
onTap: () => onMarkerTap(seller),
// The icons are coming from the FutureBuilder.
icon: isActive ? activePin : neutralPin,
);
}
class SearchMap extends StatelessWidget {
Widget build(BuildContext context) {
final paris = initialPosition ??
LatLng(parisPosition.latitude, parisPosition.longitude);
return GoogleMap(
myLocationButtonEnabled: false,
zoomControlsEnabled: false,
compassEnabled: false,
mapType: MapType.normal,
markers: markers,
initialCameraPosition: CameraPosition(target: paris, zoom: 15),
onMapCreated: onMapCreated,
onTap: (obj) => print(obj),
);
}
}
Happily it works on my devices very well, both iOS and Android. But on my reviewers devices, the icons are just not showing up. Is it a correct way to handle BitmapDescriptor? Maybe I’m wrong on the way to do this?
I have a widget named GiftGrid that shows a placeholder Text widget when it receives no items, but the test that checks for the specific case fails, even though it works fine in the app:
testWidgets('Null list shows placeholder', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
localizationsDelegates: [MyLocalizationsDelegate()],
home: GiftGrid(null)));
var a = tester.allWidgets.toList();
expect(find.text("PROPER_QUADRUPLE_CHECKED_STRING"), findsOneWidget);
});
where GiftGrid is defined as follows:
return (widget.giftList?.isEmpty ?? true)
? Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(MyLocalizations.of(context).stringThatTranslatesToSameAsTest),
),
) : StaggeredGridBuilder(...);
The debugger shows the contents of a as follows (sorry for the screenshot, I couldn't find a better way to show it):
EDIT: GifGrid receives a List as the parameter and the following test passes:
testWidgets('Gift shows thumbnail if available', (WidgetTester tester) async {
var gift = GiftModel()
..images = [
"OTHER_IMG_LINK"
]
..thumbnail =
"IMG_LINK";
// Build our app and trigger a frame.
await tester.pumpWidget(MaterialApp(
home: GiftGrid([gift]),
));
expect(find.byWidgetPredicate((widget) {
return widget is TransitionToImage &&
(widget.image as AdvancedNetworkImage).url ==
"IMG_LINK";
}), findsOneWidget);
});
I have a form that uses FocusNodes to visually indicate which part of the form is active. One field extends a PopupRoute as a kind of pop up 'keyboard'. My problem is, when I press that field, the keyboard pops up but the visual effect of the focus doesn't occur.
Some debugging from the FocusNode's listeners shows it gets focus but immediately loses it. I think it is because the new PopupRoute has a new FocusScopeNode, so my FocusNode doesn't have focus any more.
How can I keep the field focused while in the other route? I've tried:
Using FocusScope.of(context).reparentIfNeeded(focusNode) in all the build methods, which didn't do anything (I don't really understand this function tbh)
Passing the current FocusScope.of(context) into my custom PopupRoute to use. This actually worked, but after it's popped, I can't focus anything anymore (I guess it gets disposed?)
Code-wise, I'm calling requestFocus on the field tap, and adding this listener in initState:
widget.focusNode.addListener(() {
print(widget.focusNode);
if (widget.focusNode.hasFocus) {
Navigator.of(context).push(
CustomKeyboardPopupRoute(
state: widget.state,
position: //position stuff,
focusScopeNode: FocusScope.of(context), //the second of my ideas which didn't quite work above
)
).then((_) {
widget.focusNode.unfocus();
});
});
You are on the right track, indeed this happens because of the FocusScopeNode.
Make your keyboard route extend TransitionRoute:
class CustomKeyboardPopupRoute extends TransitionRoute {
#override
bool get opaque => false;
#override
Duration get transitionDuration => Duration(milliseconds: 300);
#override
Iterable<OverlayEntry> createOverlayEntries() sync* {
yield OverlayEntry(
opaque: false,
maintainState: true,
builder: _buildKeyboard,
);
}
Widget _buildKeyboard(BuildContext context) {
final positionAnimation = Tween(begin: Offset(0.0, 1.0), end: Offset.zero).animate(animation);
return SlideTransition(position: positionAnimation, child: Align(
alignment: Alignment.bottomCenter,
child: ...
),);
}
}
thanks very much.
Iterable<OverlayEntry> createOverlayEntries() sync* {
yield OverlayEntry(
opaque: false,
maintainState: true,
builder: (content) {
return ModalBarrier(dismissible: true);
}
);
yield OverlayEntry(
opaque: false,
maintainState: true,
builder: _buildContent,
);
}
I have a situation where I need to programmatically focus on a InputField(such as in response to a button press).
I'm using the Focus.moveTo function; however, even though the InputField is focused (blinking cursor appears) the keyboard is not brought up.
It seems like the best solution would be to call the RequestKeyboard() function in _InputFieldState, but this is private.
What would be the best way to accomplish this?
Here is a code sample showing the workflow:
class InputFieldWrapper extends StatefulWidget {
#override
_InputFieldWrapperState createState() => new _InputFieldWrapperState();
}
class _InputFieldWrapperState extends State<InputFieldWrapper> {
InputValue _currentInput = new InputValue(text: 'hello');
// GlobalKey for the InputField so we can focus on it
GlobalKey<EditableTextState> _inputKey = new GlobalKey<EditableTextState>();
#override
Widget build(BuildContext context) {
return new Column(
children: [
// Button that should focus on the InputField when pressed
new IconButton(
icon: new Icon(Icons.message),
onPressed: () {
Focus.moveTo(_inputKey);
},
),
// InputField that should be focused when pressing the Button
new InputField(
value: _currentInput,
key: _inputKey,
onChanged: (InputValue input) {
setState(() {
_currentInput = input;
});
}
),
],
);
}
}
This was decided to be a bug and is being tracked at #7985.