ChatGPT解决这个技术问题 Extra ChatGPT

Android:ScrollView强制到底部

我希望 ScrollView 从底部开始。有什么方法吗?

我认为它只是 scrollTo(),是的,我刚刚检查了 ScrollView 的开发文档。十分简单。

h
hungson175

您应该像这样运行 scroll.post 中的代码:

scroll.post(new Runnable() {            
    @Override
    public void run() {
           scroll.fullScroll(View.FOCUS_DOWN);              
    }
});

有一些方法不会失去焦点当前元素,当我这样做时,我会失去当前元素的焦点(不同于滚动视图)
这仅在尚未测量和布局布局的情况下才需要(例如,如果您在 onCreate 中运行它)。在按下按钮等情况下,不需要 .post() 。
如果不想关注 ScrollView,可以使用 scroll.scrollTo(0, scroll.getHeight()); 跳转到底部,或 scroll.smoothScrollTo(0, scroll.getHeight()); 以获得更平滑的滚动
这段代码不是可能的内存泄漏吗?创建一个匿名 Runnable,它包含对活动(滚动)视图的引用。如果活动在可运行对象执行其任务时被破坏,它将泄漏对滚动视图的引用,不是吗?
在 Kotlin 中:scrollView.post { scrollView.fullScroll(View.FOCUS_DOWN) }
L
Lakhwinder Singh

scroll.fullScroll(View.FOCUS_DOWN) 也应该工作。

把它放在 scroll.Post(Runnable run)

Kotlin 代码

scrollView.post {
   scrollView.fullScroll(View.FOCUS_DOWN)
}

这似乎没有任何作用,有什么建议吗?我在 onCreate 上尝试过,后来在按钮的 onClick 上尝试过。
它似乎不适用于改变方向。否则它的工作。
如果布局大小在调用它之前发生了变化,这将不起作用。它需要发布。
在您给视图完全膨胀之前,这个和下面的内容将不起作用,只是简化了 ademar 的答案。 scrollView.postDelayed(new Runnable() { @Override public void run() { scrollView.fullScroll(View.FOCUS_UP // 或向下); } }, 1000);
scroll.fullScroll(View.FOCUS_DOWN) 会导致焦点的变化。当有多个可聚焦视图(例如两个 EditText)时,这会带来一些奇怪的行为。检查我在底部提供的另一个解决方案。
d
desgraci

scroll.fullScroll(View.FOCUS_DOWN) 会导致焦点的变化。当有多个可聚焦视图(例如两个 EditText)时,这会带来一些奇怪的行为。这个问题还有另一种方法。

    View lastChild = scrollLayout.getChildAt(scrollLayout.getChildCount() - 1);
    int bottom = lastChild.getBottom() + scrollLayout.getPaddingBottom();
    int sy = scrollLayout.getScrollY();
    int sh = scrollLayout.getHeight();
    int delta = bottom - (sy + sh);

    scrollLayout.smoothScrollBy(0, delta);

这很好用。

Kotlin 扩展

fun ScrollView.scrollToBottom() {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)        
    smoothScrollBy(0, delta)
}

很高兴我不必再在这上面浪费时间了。正是我需要的
这应该有更多的赞成票。这是迄今为止最好的答案。
这是目前最好的答案。
尝试了此页面上的所有其他内容,甚至是下面的内容。这是唯一有效的方法,它不会导致我的 EditText 失去焦点。谢谢你。
如果您需要在键盘显示时向下滚动,请将此代码与 this library 结合使用。奇迹般有效。
A
Ajay Shrestha

有时 scrollView.post 不起作用

 scrollView.post(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    });

但是如果你使用scrollView.postDelayed,它肯定会工作

 scrollView.postDelayed(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    },1000);

谢谢鉴定。 postDelayed 是更好的解决方案。
@Prashant :) :) :)
请记住,您需要在完成活动时处理 Runnable
h
https

最适合我的是

scroll_view.post(new Runnable() {
     @Override
     public void run() {
         // This method works but animates the scrolling 
         // which looks weird on first load
         // scroll_view.fullScroll(View.FOCUS_DOWN);

         // This method works even better because there are no animations.
         scroll_view.scrollTo(0, scroll_view.getBottom());
     }
});

我试过这个,但这里的算法是错误的。请检查我在底部的答案。
a
ademar111190

我增量工作完美。

    private void sendScroll(){
        final Handler handler = new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {Thread.sleep(100);} catch (InterruptedException e) {}
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        scrollView.fullScroll(View.FOCUS_DOWN);
                    }
                });
            }
        }).start();
    }

笔记

这个答案是真正旧版本的android的解决方法。今天,postDelayed 没有更多的错误,您应该使用它。


不超过两个,但这在我的手机中运行良好(LG JellyBean 4.1.2 Optimus G)。
为什么不使用 scrollView.postDelayed(runnable, 100)?
当时的@MattWolfe 在某些旧版本的android 中不起作用。但是今天这个答案完全被弃用了。
看在上帝的份上,请使用 scrollView.postDelayed(runnable, 100)! :)
我添加了一条注释@AlexLockwood 我希望人们使用 postDelayed :)
Y
Yusuf Yaşar

我试过成功。

scrollView.postDelayed(new Runnable() {
    @Override
    public void run() {
        scrollView.smoothScrollTo(0, scrollView.getHeight());
    }
}, 1000);

C
Community

当视图尚未加载时,您无法滚动。您可以通过上面的帖子或睡眠电话“稍后”进行操作,但这不是很优雅。

最好计划滚动并在下一个 onLayout() 上执行。这里的示例代码:

https://stackoverflow.com/a/10209457/1310343


S
StephenDonaldHuffPhD

要考虑的一件事是不要设置什么。确保您的子控件,尤其是 EditText 控件,没有设置 RequestFocus 属性。这可能是布局上最后解释的属性之一,它将覆盖其父级(布局或 ScrollView)上的重力设置。


L
Linh

这是滚动到底部的其他一些方法

fun ScrollView.scrollToBottom() {
    // use this for scroll immediately
    scrollTo(0, this.getChildAt(0).height) 

    // or this for smooth scroll
    //smoothScrollBy(0, this.getChildAt(0).height)

    // or this for **very** smooth scroll
    //ObjectAnimator.ofInt(this, "scrollY", this.getChildAt(0).height).setDuration(2000).start()
}

使用

如果您的滚动视图已经布局

my_scroll_view.scrollToBottom()

如果您的滚动视图未完成布局(例如:您在 Activity onCreate 方法中滚动到底部...)

my_scroll_view.post { 
   my_scroll_view.scrollToBottom()          
}

T
Teo Inke

不完全是问题的答案,但我需要在 EditText 获得焦点后立即向下滚动。然而,接受的答案会使 ET 也立即失去焦点(对于我假设的 ScrollView)。

我的解决方法如下:

emailEt.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if(hasFocus){
            Toast.makeText(getActivity(), "got the focus", Toast.LENGTH_LONG).show();
            scrollView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    scrollView.fullScroll(ScrollView.FOCUS_DOWN);
                }
            }, 200);
        }else {
            Toast.makeText(getActivity(), "lost the focus", Toast.LENGTH_LONG).show();
        }
    }
});

B
BarLr

我实际上发现调用 fullScroll 两次可以解决问题:

myScrollView.fullScroll(View.FOCUS_DOWN);

myScrollView.post(new Runnable() {
    @Override
    public void run() {
        myScrollView.fullScroll(View.FOCUS_DOWN);
    }
});

它可能与执行第一次(不成功)滚动后立即激活 post() 方法有关。我认为这种行为发生在之前对 myScrollView 的任何方法调用之后,因此您可以尝试将第一个 fullScroll() 方法替换为可能与您相关的任何其他方法。


P
Phaestion

使用 Kotlin 协程还有另一种很酷的方法。与具有可运行(post/postDelayed)的 Handler 相比,使用协程的优点是它不会启动昂贵的线程来执行延迟操作。

launch(UI){
    delay(300)
    scrollView.fullScroll(View.FOCUS_DOWN)
}

将协程的 HandlerContext 指定为 UI 很重要,否则可能不会从 UI 线程调用延迟的操作。


n
nnyerges

在那些情况下,只使用 scroll.scrollTo(0, sc.getBottom()) 不起作用,使用 scroll.post

例子:

scroll.post(new Runnable() {
  @Override
  public void run() {
  scroll.fullScroll(View.FOCUS_DOWN);
  } 
});

C
Community

scroll.fullScroll(View.FOCUS_DOWN) 即使包含在 .post() 中也可能无法工作的一个可能原因是视图没有布局。在这种情况下,View.doOnLayout() 可能是更好的选择:

scroll.doOnLayout(){
    scroll.fullScroll(View.FOCUS_DOWN)
}

或者,为勇敢的灵魂提供更详细的说明:https://chris.banes.dev/2019/12/03/suspending-views/


A
Andrew

所有答案的组合对我有用:

扩展功能 PostDelayed

private fun ScrollView.postDelayed(
    time: Long = 325, // ms
    block: ScrollView.() -> Unit
) {
    postDelayed({block()}, time)
}

扩展函数 measureScrollHeight

fun ScrollView.measureScrollHeight(): Int {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)
    return delta
}

扩展功能 ScrolltoBottom

fun ScrollView.scrollToBottom() {
    postDelayed {
        smoothScrollBy(0, measureScrollHeight())
    }
}

请注意,最小延迟应至少为 325 毫秒,否则滚动会出错(不会滚动到整个底部)。当前高度和底部之间的增量越大,延迟时间应该越大。


C
Crabster

这里有人说 scrollView.post 不起作用。

如果您不想使用 scrollView.postDelayed,另一种选择是使用侦听器。这是我在另一个用例中所做的:

ViewTreeObserver.OnPreDrawListener viewVisibilityChanged = new ViewTreeObserver.OnPreDrawListener() {
    @Override
    public boolean onPreDraw() {
        if (my_view.getVisibility() == View.VISIBLE) {
            scroll_view.smoothScrollTo(0, scroll_view.getHeight());
        }
        return true;
    }
};

您可以通过以下方式将其添加到您的视图中:

my_view.getViewTreeObserver().addOnPreDrawListener(viewVisibilityChanged);

J
Jemshit Iskenderov

如果您的最低 SDK 为 29 或更高版本,您可以使用:

View childView = findViewById(R.id.your_view_id_in_the_scroll_view)
if(childView != null){
  scrollview.post(() -> scrollview.scrollToDescendant(childView));
}

A
Audi Nugraha

这立即起作用。不延误。

// wait for the scroll view to be laid out
scrollView.post(new Runnable() {
  public void run() {
    // then wait for the child of the scroll view (normally a LinearLayout) to be laid out
    scrollView.getChildAt(0).post(new Runnable() {
      public void run() {
        // finally scroll without animation
        scrollView.scrollTo(0, scrollView.getBottom());
      }
    }
  }
}