Flutter ListView touch listener - dart

How can I find that the user has lifted his finger off the screen after scrolling the ListView. I want to use ScrollController.jumpTo(...) when this event happens. And I couldn't find any callback like this.
PS: I tried using GestureDetector but nothing worked.

I found that.
ScrollController.position.isScrollingNotifier.addListener(() {// scrolling stopped});
If anyone knows a better solution please write it down. I am more than happy to accept your answer.

Wrap your ListView in NotificationListener and listens for UserScrollNotification.
NotificationListener<UserScrollNotification>(
onNotification: (notification) {
if (notification.direction == ScrollDirection.idle) {
print("Scrolling stopped");
}
},
child: ListView.builder(...),
),

Related

Update UI rendering in React Natives 'focus' Event Listener

I am navigating from different class objects (screens) within my React Native App. Once I navigate to a given screen, I want to execute different functions including Activity Indicators to show that the function is still running.
Therefore is set up a focus Event Listener which is called every time I navigate back to my screen. My current problem is that my Activity Indicators are not updated within the focus Event but directly after, which is not my wanted behavior as I have to wait for my functions to end without any visual indicator.
class Homescreen extends Component {
constructor(props){
super(props};
this.state = {
showIndicator: false;
}
}
componentDidMount(){
this.props.navigation.addListener('focus', this._onFocus);
}
componentWillUnmount(){
this.props.navigation.removeListener('focus', this._onFocus);
}
_onFocus = async () => {
this.setState({showIndicator: true});
asyncFunc();
};
async asyncFunc(){
//calling a function from swift which calls a C function inside DispatchQeue.main.async
//inside my C function I successfully set my ActivityIndicator to false with an Event which calls
//this.setState({showIndicator: false});
}
render(){
console.log(this.state.showIndicator); // correct value is printed while I wait inside the ```focus``` Event to finish, but the UI is not updated.
return(
{this.state.showIndicator && <ActivityIndicator/>}
)
}
}
I receive the correct current status of showIndicatorbut before the focus Event is not finished, my render does not redraw.
To me it seems like the UI won't update until I am out of my focus Event. How can I reach my goal of displaying the ActivityIndicator before the focus Event or how do I call my function right after the focus Event?
I can achieve my wanted behavior by using the blurevent and setting my ActivityIndicator visible while moving to another screen and after moving back I wait until my function is finished and remove the ActivityIndicator but this seems like a bad workaround and also I can see the ActivityIndicator when moving which might be confusing.
You should replace curly braces around this statement {this.state.showIndicator && } and check.
If it doesn't work accordingly then let me know.

Nativescript Angular Detect Swipe to Back for IOS

In Nativescript Angular, I can swipe from left edge to right to go back on iOS. Is there any way i can detect or capture this swipe back?
The reason for this is because I have a button on screen that execute "this.routerExtensions.back()" when tapped. I would like to identify whether a "Back action" is from this button or iOS swipe event.
Thanks
NativeScript has this property on pages.
https://docs.nativescript.org/api-reference/classes/ui_page.page.html#enableswipebacknavigation
If you set that to false, you should then be able to create your own gesture for going back. Even on native iOS, I am not sure you can directly tap into the back gesture without instead replacing it with your own.
This is how I was able to solve it for Android and iOS:
adjust constructor to manipulate the pullToLeft function from Android, and disable the default swipe back from iOS:
constructor(...) {
if (isAndroid) {
Application.android.on(
AndroidApplication.activityBackPressedEvent,
(data: AndroidActivityBackPressedEventData) => {
data.cancel = true;
...yourCustomFunction()
}
);
} else {
page.enableSwipeBackNavigation = false;
}
}
for Android it is already working - for iOS you need then to write a function you can use on a template (this is also how you can recognize the swipe action):
public onSwipe = (args: SwipeGestureEventData) => {
if (!isAndroid) {
if (args.direction === SwipeDirection.right) {
...yourCustomFunction()
}
}
};
disable the default PopGestureSerializer and add the swipe function on top of your template/element and it should work on iOS as well:
<StackLayout [interactivePopGestureRecognizer]="false" (swipe)='onSwipe($event)'>
...
</StackLayout>

Multiple entity-bound CupertinoTextFields that save on focus out

I have a list of some entries I want edit on focus out. I createe FocusNode for each entry, CupertinoTextField for each entry too.
var textField = (UserMotivator um) {
var controller;
var focusNode = new FocusNode();
focusNode.addListener(() {
if (!focusNode.hasFocus) {
post(um);
}
});
var controller = TextEditingController(text: um.text);
return CupertinoTextField(
focusNode: focusNode,
controller: controller,
onChanged: (String value) {
um.text = value;
}
);
};
For some weird reason, in simulator (not tested on real device), when I click on many of these TextFields, I get this:
How do I bound a focus out even to a TextField without using FocusNode/ without having all of these cursors blinking?
So I resolved the issue I think. The reason it was buggy was that I was on v1.1.8, after updating to v1.5.4 it somehow got fixed, was not perfect but was better. After I moved the FocusNodes creation code form build to initState method it got even better but the cursor was still blinking at the start of the TextField. This was because I had called setState in the onChange handler, which somehow caused the TextField to redraw and act so weirdly.

Flutter restarts state of TextField when keyboard is shown and then gone

So I'm working on a TextField with scoped_model. I moved the controller to the Model class, and I'm trying to change the state of a Text with the text the user inputs on said TextField. But when I close the keyboard, the state changes and the TextField is now empty, so nothing is seen on the Text widget either. This is my code:
CupertinoTextField(
controller: model.lastNameController,
onChanged: (text) => model.changeShortLastNameState(lastName: text),
),
And this is the relevant code on my Model
final lastNameController = TextEditingController();
void changeShortLastNameState({String lastName}) {
var splitLastName = lastName.split(' ');
var shortLastName = splitLastName[0];
this.shortLastName = shortLastName;
notifyListeners();
}
I found someone on the flutter github with the same issue, but they sent him to SO, and I haven't been successful on finding a question by the same guy. Does anyone know how to solve this issue? Thanks.
Use the deceleration of text editing controller out side of build function.

Flutter: How to prevent banner ad from showing if view is already disposed

I am currently experimenting with banner ads from the firebase_admob plugin. The process to show and dispose them is pretty straightforward, I do it in initState() and dispose().
The code to create and display the add looks like this:
_bannerAd = createBannerAd();
_bannerAd
..load().then((loaded) {
if (loaded) {
_bannerAd..show();
}
});
However, as I am calling show() asynchronously, it is possible that the view was already closed when the ad is being shown (i.e. by clicking back button really fast). In that case, the dispose() method will never be called and the ad will be "stuck" on the bottom of the screen.
How can I solve this problem? Am I using the banner ad wrong or is it possible to detect if the view was already changed? I tried using the "mounted" property of the state but it didn't seem to work.
Just check "this.mounted" property of state class before showing the add.
_bannerAd = createBannerAd();
_bannerAd
..load().then((loaded) {
if (loaded && this.mounted) {
_bannerAd..show();
}
});
From https://github.com/flutter/flutter/issues/21474#issuecomment-535188820, that's a little hack but it works for me.
You can add a little delay in your dispose method like this:
static void hideBannerAd() {
Future.delayed(Duration(milliseconds: 500), () {
if (_bannerAd != null) _bannerAd.dispose();
_bannerAd = null;
});
}
500 milliseconds is enough.

Resources