I would like to make some kind of custom scroll progress indicator for CustomScrollView.
_scrollController = ScrollController()..addListener(_scroll);
void _scroll() {
print('scrolled ${_scrollController.offset} from {??}');
}
Is there way to findout _scrollController max offset?
Or could I get some value form Scrollbar widget?
So all you need is
scrollController.position.maxScrollExtent
This gives you the max scroll extent for the ListView
Related
How can I detect when a ListView is scrolled?
I tried wrapping the ListView in a ScrollView and using the scroll event on the ScrollView. Doesn't work.
I've used the PanGesture on a ListView to capture when a user is scrolling up or down.
const panEvent$ = fromEvent(this.listView, 'pan').pipe(map(
(event: PanGestureEventData) => event.deltaY
));
This will take my listView property and only emit the Y values. you can then determine if they are moving up or down if Y is greater than 0
This question already has answers here:
Flutter Keyboard listen on hide and show
(8 answers)
Closed last year.
I have a BottomNavigationBar at the upper-most level of my application. I want to detect keyboard open and close basically anywhere in the app/subtree, so I can show and hide the BottomNavigationBar whenever the keyboard is visible.
This is a general issue and may not be directly related to the BottomNavigationBar. In other words, abstract from the BottomNavigationBar :-)
To check for keyboard visibility, just check for the viewInsets property anywhere in the widget tree. The keyboard is hidden when viewInsets.bottom is equal to zero.
You can check for the viewInsets with MediaQuery like:
MediaQuery.of(context).viewInsets.bottom
I just created a Flutter plugin to notify about keyboard open and close events. It works both on Android and iOS.
keyboard_visibility
import 'package:keyboard_visibility/keyboard_visibility.dart';
#override
void initState() {
super.initState();
KeyboardVisibilityNotification().addNewListener(
onChange: (bool visible) {
print(visible);
},
);
}
You can use WidgetsBinding.instance.window.viewInsets.bottom. If its value is greater than 0.0 then the keyboard is visible.
if(WidgetsBinding.instance.window.viewInsets.bottom > 0.0)
{
// Keyboard is visible.
}
else
{
// Keyboard is not visible.
}
You can use the keyboard_visibility package to do this effectively. I've used it, and it works like a charm.
To install
dependencies:
keyboard_visibility: ^0.5.2
Usage
import 'package:keyboard_visibility/keyboard_visibility.dart';
#protected
void initState() {
super.initState();
KeyboardVisibilityNotification().addNewListener(
onChange: (bool visible) {
print(visible);
},
);
}
It also supports listeners like show/hide.
Here is the link.
In your StatefullWidget, create a variable:
bool _keyboardVisible = false;
Then initialize that variable in the build widget;
#override
Widget build(BuildContext context) {
_keyboardVisible = MediaQuery.of(context).viewInsets.bottom != 0;
return child;
}
This is my solution, which uses WidgetsBindingObserver to observe window size changes, and determine whether the keyboard is hidden based on this.
/// My widget state,it can remove the focus to end editing when the keyboard is hidden.
class MyWidgetState extends State<MyWidget> with WidgetsBindingObserver {
/// Determine whether the keyboard is hidden.
Future<bool> get keyboardHidden async {
// If the embedded value at the bottom of the window is not greater than 0, the keyboard is not displayed.
final check = () => (WidgetsBinding.instance?.window.viewInsets.bottom ?? 0) <= 0;
// If the keyboard is displayed, return the result directly.
if (!check()) return false;
// If the keyboard is hidden, in order to cope with the misjudgment caused by the keyboard display/hidden animation process, wait for 0.1 seconds and then check again and return the result.
return await Future.delayed(Duration(milliseconds: 100), () => check());
}
#override
void initState() {
super.initState();
// Used to obtain the change of the window size to determine whether the keyboard is hidden.
WidgetsBinding.instance?.addObserver(this);
}
#override
void dispose() {
// stop Observing the window size changes.
WidgetsBinding.instance?.removeObserver(this);
super.dispose();
}
#override
void didChangeMetrics() {
// When the window insets changes, the method will be called by the system, where we can judge whether the keyboard is hidden.
// If the keyboard is hidden, unfocus to end editing.
keyboardHidden.then((value) => value ? FocusManager.instance.primaryFocus?.unfocus() : null);
}
}
You can use MediaQuery.of(context).viewInsets.bottom. Just look at the documentation below.
/// The parts of the display that are completely obscured by system UI, /// typically by the device's keyboard. /// /// When a
mobile device's keyboard is visible viewInsets.bottom ///
corresponds to the top of the keyboard. /// /// This value is
independent of the [padding]: both values are /// measured from the
edges of the [MediaQuery] widget's bounds. The /// bounds of the top
level MediaQuery created by [WidgetsApp] are the /// same as the
window (often the mobile device screen) that contains the app. ///
/// See also: /// /// * [MediaQueryData], which provides some
additional detail about this /// property and how it differs from
[padding]. final EdgeInsets viewInsets;
You can use
Flutter keyboard visibility plugin
#override
Widget build(BuildContext context) {
return KeyboardVisibilityBuilder(
builder: (context, isKeyboardVisible) {
return Text(
'The keyboard is: ${isKeyboardVisible ? 'VISIBLE' : 'NOT VISIBLE'}',
);
}
);
With Flutter 2.0 and null safety, I use this package - it has no streams, pure Dart, gives additional information about keyboard height, etc.
flutter_keyboard_size 1.0.0+4
I used a workaround. I added a focusNode to the input and added a listener to that.
See the implementation here add focus listener to input.
I found an easier solution here:
Put the DesiredBottomWidget in a Stack() with a Positioned(top: somevalue), and it will be hidden when the keyboard appears.
Example:
Stack(
"Somewidget()",
Positioned(
top: "somevalue",
child: "DesiredBottomWidget()"),
),
I have added a popup window to my main UI as follows:
Window component = new Window();
UI.getCurrent().addWindow(component);
Now, I want my popup to be centered horizontally and e.g. 40 pixels from the top of the screen. As far as I can see Vaadin has 4 methods for positioning my window.
component.center()
component.setPosition(x, y)
component.setPositionX(x)
component.setPositionY(y)
None of these are really what I want. I was hoping at first that setPositionY might help me. This does allow me to get the right distance from the top, but the x-position is now set to 0, where I wanted it to be centered.
The setPosition might have helped if I was able to calculate what the x-position should be, but this would require me to know the width of the component in pixels, but component.getWidth just tells me 100%.
Next I tried to use CSS styling on the component, writing and explicit css rule and adding it to the component with addStyleName. It seems though that Vaadin overrides whatever I wrote in my css with its own defaults...
Any ideas how to get my Window component positioned correctly?
I used the methods getBrowserWindowWidth() and getBrowserWindowHeight() from the com.vaadin.server.Page class for this.
I centered my "log" window horizontally in the lower part of the browser window with
myWindow.setHeight("30%");
myWindow.setWidth("96%");
myWindow.setPosition(
(int) (Page.getCurrent().getBrowserWindowWidth() * 0.02),
(int) (Page.getCurrent().getBrowserWindowHeight() * 0.65)
);
Solution 1: Use SizeReporter
Indeed, setPositionY() will reset the window's centered property to false. As the width of your pop-up and that of your browser window are not know before they appear on the screen, the only way I know to get those values is to use the SizeReporter add-on. Its use is quite straightforward:
public class MyUI extends UI {
private Window popUp;
private SizeReporter popUpSizeReporter;
private SizeReporter windowSizeReporter;
#Override
protected void init(VaadinRequest request) {
Button button = new Button("Content button");
VerticalLayout layout = new VerticalLayout(button);
layout.setMargin(true);
popUp = new Window("Pop-up", layout);
popUp.setPositionY(40);
addWindow(popUp);
popUpSizeReporter = new SizeReporter(popUp);
popUpSizeReporter.addResizeListenerOnce(this::centerPopUp);
windowSizeReporter = new SizeReporter(this);
windowSizeReporter.addResizeListenerOnce(this::centerPopUp);
}
private void centerPopUp(ComponentResizeEvent event) {
int popUpWidth = popUpSizeReporter.getWidth();
int windowWidth = windowSizeReporter.getWidth();
if (popUpWidth == -1 || windowWidth == -1) {
return;
}
popUp.setPositionX((windowWidth - popUpWidth) / 2);
}
}
This piece of code will be okay as long as you don't resize the pop-up. If you do, it will not be automatically recentered. If you replace addResizeListenerOnce() by addResizeListener() then it will automatically recenter the pop-up but you'll get some "UI glitches" as the add-on sends resize events almost continually while you're resizing your pop-up...
You could try to do it using CSS, but I personally avoid CSS as much as I can with Vaadin :).
You'll need to recompile the widgetset after you've added the add-on as a dependency.
Solution 2: Use com.vaadin.ui.JavaScript
I won't vouch for the portability of this solution but I guess it will work on most modern browsers.
public class MyUI extends UI {
private Window popUp;
#Override
protected void init(VaadinRequest request) {
Button button = new Button("Content button");
VerticalLayout layout = new VerticalLayout(button);
layout.setMargin(true);
popUp = new Window("Pop-up", layout);
popUp.setPositionY(40);
popUp.addStyleName("window-center");
addWindow(popUp);
// Add a JS function that can be called from the client.
JavaScript.getCurrent().addFunction("centerWindow", args -> {
popUp.setPositionX((int) ((args.getNumber(1) - args.getNumber(0)) / 2));
});
// Execute the function now. In real code you might want to execute the function just after the window is displayed, probably in your enter() method.
JavaScript.getCurrent().execute("centerWindow(document.getElementsByClassName('window-center')[0].offsetWidth, window.innerWidth)");
}
}
I am attempting to implement a chat view in Windows Phone 8. When a user taps my TextBox at the bottom of my View, the view shifts vertically as the keyboard appears, but an additional amount of padding appears at the bottom of the view. I have seen this happen in other apps as well.
Here is my app:
Here is an equivalent app (Whatsapp) that has clearly solved the problem.
Anyone have any ideas on how to correct this issue in a way that won't break my view? My attempts to manually modify padding when Focused/Unfocused have not been successful.
Good news! I have managed to figure out a fix for this. The below code stops the page from being moved up at all and then adds a margin to the bottom of the text box to place it above the keyboard. The value below of 417 seems to work well for me but you can change this to whatever you like. Using this method also stops other content being pushed off screen like the conversation as it will be fully scrollable while the keyboard is active.
private void TextBox_GotFocus_1(object sender, RoutedEventArgs e)
{
var rootFrame = Application.Current.RootVisual as PhoneApplicationFrame;
rootFrame.RenderTransform = new CompositeTransform() { TranslateY = +0 };
TextInput2.Margin = new Thickness(12, 0, 12, 417);
}
private void TextBox_LostFocus_1(object sender, RoutedEventArgs e)
{
var rootFrame = Application.Current.RootVisual as PhoneApplicationFrame;
rootFrame.RenderTransform = new CompositeTransform() { TranslateY = +0 };
TextInput2.Margin = new Thickness(12, 0, 12, 12);
}
You can always try to give bottom margin with negative value. example give -40px and see.
If you're using Grid, set Height to "Auto" where the TextBox is.
Set InputScope="Default".
I am using a ListField for my app to show the data in a list. Now my requirement is that i want to increase the row height of the selected item of the list.
For this, i created a GridFieldManager and populated my list using this manager. I then override the onFocus() method of this manager. But, this method is never invoked. As a result i am unable to increase the height of the selected row item.
Please help.
ListField rows are all designed to be uniformly sized, so unfortunately you won't be able to directly change the size of one row. It's possible you can emulate it by setting it so that the row above and below draw a little bit of the focus color at the bottom and top respectively. Alternatively, you could have one field that just stays centered above whatever row is focused. Then redraw this "floating Field" with the information from the selected row.
I got it working. I faked the ListField implementation. I removed ListField and replaced it with VerticalFieldManager. I adjusted its size during onfocus() and onUnfocus() and used sublayout() to change the height of this manager. Its working exactly the way i want.
you can increase the row height/font text/...
as ultimately, all of the api's call canvas's paint methods
how to do:
//try playing with the font_type,font height
Font myFont = Font.getDefault().derive(Font.PLAIN, 14, Ui.UNITS_px);
private class ListCallback implements ListFieldCallback {
public void drawListRow(ListField list, Graphics g, int index, int y, int w) {
g.setFont(myFont);
String text = (String)listElements.elementAt(index);
g.drawText(text, 0, y, 0, w);
//you can increase the height of a particular row in the height parameter.
// if you want it to be specific, put an 'if conditon'
EX: if(index=1)
{
w+=10;
}
}
}