加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

dart – 如何在Flutter的滚动视图中限制滚动距离?

发布时间:2020-12-14 14:51:31 所属栏目:百科 来源:网络整理
导读:我创建了一个页面,其中包含一个列中的几个文本字段和按钮,该列包含在具有背景图像的容器中.而这个容器本身就是一个scrollview小部件的子代. 因此,当一个人点击其中一个字段时,他们的键盘会弹出(占据屏幕的一部分),这意味着一些按钮/字段在屏幕外,这是scrollv
我创建了一个页面,其中包含一个列中的几个文本字段和按钮,该列包含在具有背景图像的容器中.而这个容器本身就是一个scrollview小部件的子代.

因此,当一个人点击其中一个字段时,他们的键盘会弹出(占据屏幕的一部分),这意味着一些按钮/字段在屏幕外,这是scrollview小部件用于其目的的地方.

这里的问题是我想限制滚动视图允许用户滚动的距离.

最低按钮下面有一些空白区域,我不希望用户能够一直滚动到那里.这也是让体验变得简单,并且不会让用户“过度滚动”超过他应该输入的字段.

但由于背景图像是滚动视图的一部分,因此视图将允许用户向下滚动到图像底部.我想限制这个.

作为后续工作,我试图弄清楚如何设置初始滚动位置. (因此,当单击某个字段时,滚动视图会向下滚动到第一个文本字段,因此所有字段都在视图中.用户无需向下滚动它们.但我不希望重新应用此滚动位置每当用户点击某个字段时,当然.)

这是相关的(如果我的任何代码看起来非常糟糕请说出来,我是一般的编程新手并接受任何建议改进):

class LoginPageConstructor extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    AssetImage loginBackgroundAsset =
        new AssetImage("assets/loginscreen/backgroundrock.png");
//    var _scrollController = new ScrollController(
//        initialScrollOffset: 200.0,//        keepScrollOffset: true);
    return new Scaffold(
        body: new Container(
      child: new ListView(key: new PageStorageKey("Divider 1"),//        controller: _scrollController,children: <Widget>[
          new Stack(children: <Widget>[
            new Container(
            constraints: new BoxConstraints.expand(height: 640.0),decoration: new BoxDecoration(
                  image: new DecorationImage(
                      image: loginBackgroundAsset,fit: BoxFit.cover)),child: new Column(
              children: <Widget>[
                new Divider(height: 300.0,),new Center(child: new UsernameText(),new Divider(height: 8.0,new Center(child: new PasswordText(),new Divider(),new LoginButton(),new SignUpButton(),],))
          ])
        ],));
  }
}

解决方法

对于自动滚动字段进入视图,听起来你正在和 issue 10826搏斗.我在这个问题上发布了 workaround.我将解决方法改为您的示例代码;见下文. (你可能想稍微调整一下.)

如果您想阻止用户滚动,您可能只想确保使用下面相同的技术可见所有字段,然后使用NeverScrollableScrollPhysics作为ListView的物理.或者,如果你有野心,你可以实现自定义滚动物理,如Gallery example所示.如果我是你,我会坚持#10826被修复.

video

import 'package:meta/meta.dart';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
  runApp(new MaterialApp(home: new LoginPage()));
}

/// A widget that ensures it is always visible when focused.
class EnsureVisibleWhenFocused extends StatefulWidget {
  const EnsureVisibleWhenFocused({
    Key key,@required this.child,@required this.focusNode,this.curve: Curves.ease,this.duration: const Duration(milliseconds: 100),}) : super(key: key);

  /// The node we will monitor to determine if the child is focused
  final FocusNode focusNode;

  /// The child widget that we are wrapping
  final Widget child;

  /// The curve we will use to scroll ourselves into view.
  ///
  /// Defaults to Curves.ease.
  final Curve curve;

  /// The duration we will use to scroll ourselves into view
  ///
  /// Defaults to 100 milliseconds.
  final Duration duration;

  EnsureVisibleWhenFocusedState createState() => new EnsureVisibleWhenFocusedState();
}

class EnsureVisibleWhenFocusedState extends State<EnsureVisibleWhenFocused> {
  @override
  void initState() {
    super.initState();
    widget.focusNode.addListener(_ensureVisible);
  }

  @override
  void dispose() {
    super.dispose();
    widget.focusNode.removeListener(_ensureVisible);
  }

  Future<Null> _ensureVisible() async {
    // Wait for the keyboard to come into view
    // TODO: position doesn't seem to notify listeners when metrics change,// perhaps a NotificationListener around the scrollable could avoid
    // the need insert a delay here.
    await new Future.delayed(const Duration(milliseconds: 600));

    if (!widget.focusNode.hasFocus)
      return;

    final RenderObject object = context.findRenderObject();
    final RenderAbstractViewport viewport = RenderAbstractViewport.of(object);
    assert(viewport != null);

    ScrollableState scrollableState = Scrollable.of(context);
    assert(scrollableState != null);

    ScrollPosition position = scrollableState.position;
    double alignment;
    if (position.pixels > viewport.getOffsetToReveal(object,0.0)) {
      // Move down to the top of the viewport
      alignment = 0.0;
    } else if (position.pixels < viewport.getOffsetToReveal(object,1.0)) {
      // Move up to the bottom of the viewport
      alignment = 1.0;
    } else {
      // No scrolling is necessary to reveal the child
      return;
    }
    position.ensureVisible(
      object,alignment: alignment,duration: widget.duration,curve: widget.curve,);
  }

  Widget build(BuildContext context) => widget.child;
}

class LoginPage extends StatefulWidget {
  LoginPageState createState() => new LoginPageState();
}

class LoginPageState extends State<LoginPage> {
  FocusNode _usernameFocusNode = new FocusNode();
  FocusNode _passwordFocusNode = new FocusNode();

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Example App'),body: new Container(
        child: new ListView(
          physics: new NeverScrollableScrollPhysics(),key: new PageStorageKey("Divider 1"),children: <Widget>[
            new Container(
              constraints: new BoxConstraints.expand(height: 640.0),decoration: new BoxDecoration(
                image: new DecorationImage(
                  image: new NetworkImage(
                    'https://flutter.io/images/flutter-mark-square-100.png',fit: BoxFit.cover,child: new Column(
                children: <Widget>[
                  new Container(
                    height: 300.0,new Center(
                    child: new EnsureVisibleWhenFocused(
                      focusNode: _usernameFocusNode,child: new TextFormField(
                        focusNode: _usernameFocusNode,decoration: new InputDecoration(
                          labelText: 'Username',new Container(height: 8.0),new Center(
                    child: new EnsureVisibleWhenFocused(
                      focusNode: _passwordFocusNode,child: new TextFormField(
                        focusNode: _passwordFocusNode,obscureText: true,decoration: new InputDecoration(
                          labelText: 'Password',new Container(),new RaisedButton(
                    onPressed: () {},child: new Text('Log in'),child: new Text('Sign up'),);
  }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读