如何滚动到长 ScrollView 布局的顶部?

Posted

技术标签:

【中文标题】如何滚动到长 ScrollView 布局的顶部?【英文标题】:How to scroll to top of long ScrollView layout? 【发布时间】:2011-05-06 09:19:17 【问题描述】:

对于我的应用程序的一部分,用户会看到一个名称列表,并要求用户按照他们认为合适的方式对它们进行分组。

(注意,ListView 代码是从 android 视图教程中逐字复制的。我还没有根据我的需要对其进行自定义,我只是想弄清楚如何使它工作。)

基本布局是一个LinearLayout,包含一个ScrollView(在下面的代码中称为“groupsScrollView”),包含一个RelativeLayout。我有一些按钮和文本,然后是下面的 ListView,它显示名称列表。所有这些都高于可见屏幕区域,因此允许用户垂直滚动以查看所有内容。

这一切都很好,除了页面加载时它总是预先滚动到我的 ListView 的顶部 - 在页面的中间。我创建的告诉用户该做什么的文本和按钮是不可见的。

我可以抓住屏幕并向上滚动,效果很好,但我希望屏幕加载已经滚动到顶部。用户不必向上滚动即可看到新加载页面的顶部。但是我尝试以编程方式滚动到屏幕顶部的所有操作都失败了。

这是我的 onCreate 方法:

protected void onCreate(Bundle savedInstanceState) 

    super.onCreate(savedInstanceState);

    setContentView(R.layout.groups);

    mainScrollView = (ScrollView)findViewById(R.id.groupsScrollView);

    //get the Bundle out of the Intent...
    Bundle extras = getIntent().getExtras();
    mNames = extras.getStringArray("mNames");

    setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, mNames));

    ListView lv = getListView();
    lv.setTextFilterEnabled(true);

    //This is the line I'm having issues with
    mainScrollView.pageScroll(View.FOCUS_UP);

    lv.setOnItemClickListener(new OnItemClickListener() 
        public void onItemClick(AdapterView<?> parent, View view,
            int position, long id) 
          // When clicked, show a toast with the TextView text
          Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
              Toast.LENGTH_SHORT).show();
        
      );

“mainScrollView.pageScroll(View.FOCUS_UP); 行是问题。它不会导致错误,但它似乎没有做任何事情。我试过 scrollTo(0,0), scrollDirection( View.FOCUS_UP),以及我能想到的所有其他内容。

由于我没有收到错误消息,我不得不假设这些滚动命令实际上正在工作,但它们滚动到 ListView 的顶部,而不是滚动到包含它的 ScrollView 或 RelativeLayout 的顶部。谷歌自己对 scrollTo(int x, int y) 方法的描述似乎证实了这一点,他们说“这个版本也将滚动限制在我们孩子的范围内。”。

所以,为了让一个更长的问题变得更长,我如何在 ScrollView 中包含的屏幕上加载一堆视图,然后以编程方式将整个内容滚动到页面顶部,以便用户可以与之交互?

谢谢!

【问题讨论】:

【参考方案1】:

我在 Kotlin 中这样解决了我的问题:

scrollview.isFocusableInTouchMode = true
scrollview.fullScroll(View.FOCUS_UP)
scrollview.smoothScrollTo(0,0)

你也可以像这样创建一个扩展:

ScrollView.moveToTop()

    this.isFocusableInTouchMode = true
    this.fullScroll(View.FOCUS_UP)
    this.smoothScrollTo(0,0)

并像这样使用它:

scrollView.moveToTop()

【讨论】:

【参考方案2】:

此解决方案也适用于 NestedScrollView

NestedScrollView nestedScrollView = view.findViewById(R.id.YourNestedScrollViewID);
nestedScrollView.fullScroll(ScrollView.FOCUS_UP);

【讨论】:

【参考方案3】:

scrollViewObject.fullScroll(ScrollView.FOCUS_UP) 这工作正常,但这一行的唯一问题是,当数据填充到 scrollViewObject 时,已立即调用。您必须等待几毫秒才能填充数据。试试这个代码:

scrollViewObject.postDelayed(new Runnable() 
    @Override
    public void run() 
        scroll.fullScroll(ScrollView.FOCUS_UP);
    
, 600);

 scrollViewObject.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() 
    @Override
    public void onGlobalLayout() 
        scrollViewObject.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        scrollViewObject.fullScroll(View.FOCUS_UP);
    
);

【讨论】:

我正在处理滚动视图应该滚动到页面底部的相同问题,将其修复! View 对象提供了一个 post(Runnable) 方法,您可以使用该方法,而不是猜测“神奇”x 您必须等待的毫秒数,该方法将在小部件在 UI 上呈现后发布可运行对象. @Ryan : post(Runnable) 在 Nexus 5 (Genymotion) 上对我总是不起作用 post(Runnable) 可能不起作用,因为如果您在视图膨胀步骤之后获取数据,则首先向上滚动工作,然后数据填充到视图中。所以你要么你应该使用 postDelayed(Runnable,dummyMillis) 要么你应该在数据填充过程之后使用 scroll.fullScroll(ScrollView.FOCUS_UP)。 您提供静态毫秒的第一个解决方案是一种糟糕的方法。【参考方案4】:

这对我有用

scroll_view.smoothScrollTo(0,0); // scroll to top of screen

【讨论】:

【参考方案5】:
scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() 
    @Override
    public void onGlobalLayout() 
        // Ready, move up
        scrollView.fullScroll(View.FOCUS_UP);
    
);

【讨论】:

【参考方案6】:

这是 scrollview 的强制滚动:

            scrollView.post(new Runnable() 
                @Override
                public void run() 
                    scrollView.scrollTo(0, 0);
                    scrollView.pageScroll(View.FOCUS_UP);
                    scrollView.smoothScrollTo(0,0);
                
            );

【讨论】:

【参考方案7】:
@SuppressWarnings( "deprecation", "unchecked" )
public void swipeTopToBottom(AppiumDriver<MobileElement> driver) 
                    throws InterruptedException 
       Dimension dimensions = driver.manage().window().getSize();
        Double screenHeightStart = dimensions.getHeight() * 0.30;
        int scrollStart = screenHeightStart.intValue();
        System.out.println("s="+scrollStart);
        Double screenHeightEnd = dimensions.getHeight()*0.90;
        int scrollEnd = screenHeightEnd.intValue();
        driver.swipe(0,scrollStart,0,scrollEnd,2000);
        CommonUtils.threadWait(driver, 3000);
    

【讨论】:

这肯定会运行, 请简要说明此答案如何解决问题。【参考方案8】:

很简单

    ScrollView scroll = (ScrollView) findViewById(R.id.addresses_scroll);
    scroll.setFocusableInTouchMode(true);
    scroll.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);

【讨论】:

对我来说它不起作用(第 3 行),解决方案是:scroll.fullScroll(View.FOCUS_UP); (包括你的前 2 行) @medskill,嗨,你把这些写在你的 xml 文件中了吗?我发现这只适用于onCreate() @imknownJ.Kimu 在 xml 文件中为我工作 这对我有用。您需要第二行和第三行。它不适用于我的 XML。 如果可以,我会吻你!在这上面花了 1-2 个小时。等待两个列表视图加载并且不想专注于它们时最好的一个。将其添加到 onResume() 中。【参考方案9】:

我有同样的问题,这解决了它。希望对你有帮助。

listView.setFocusable(false);

【讨论】:

这也是 gridviews 的正确解决方案。当您在同一视图组中有多个视图元素时会发生这种情况,尤其是列表或网格视图顶部的另一个列表视图。由于适配器通知 UI 线程,视图被重新创建并向上滚动到第一个元素。只需调用 listView.setFocusable(false) / gridView.setFocusable(false)。如果您从 xml 文件中执行此操作,则将无法正常工作。 这个解决方案也适用于我的情况,我在 NestedScrollView 中有 RecyclerView,所以它会自动向下滚动。谢谢,伙计! 我必须在设置适配器之前添加它,但之后就像一个魅力。谢谢 完美解释!! 感谢 Miguel 和特别是 omersem 的解释,特别是关于如果在 XML 中设置它将如何工作的部分,这让我有些头疼【参考方案10】:
 final ScrollView scrollview = (ScrollView)findViewById(R.id.selected_place_layout_scrollview);

         scrollview.post(new Runnable()  
                public void run()  
                    scrollview.scrollTo(0, 0); 
                 
            ); 

【讨论】:

【参考方案11】:
runOnUiThread( new Runnable()
   @Override
   public void run()
      mainScrollView.fullScroll(ScrollView.FOCUS_UP);
   

【讨论】:

【参考方案12】:

试试

mainScrollView.fullScroll(ScrollView.FOCUS_UP);

它应该可以工作。

【讨论】:

也适合我。 :D 我发现 ScrollView#fullScroll() 改变了当前焦点。我用 EditText 测试过。【参考方案13】:

所有这些有效解决方案的主要问题是,当滚动条尚未绘制在屏幕上时,您正试图向上移动它。

您需要等到滚动视图出现在屏幕上,然后使用任何这些解决方案将其向上移动。这是比后延迟更好的解决方案,因为您不介意延迟。

    // Wait until my scrollView is ready
    scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() 
        @Override
        public void onGlobalLayout() 
            // Ready, move up
            scrollView.fullScroll(View.FOCUS_UP);
        
    );

【讨论】:

不错的解决方案 - 不要忘记在 onGlobalLayout 方法调用 scrollView.getViewTreeObserver().removeOnGlobalLayoutListener(this); 结束时删除全局侦听器【参考方案14】:

当我在 View Flipper 或 Dialog 中使用 Scrollview 时,我遇到了同样的问题 scrollViewObject.fullScroll(ScrollView.FOCUS_UP) 返回 false ,因此 scrollViewObject.smoothScrollTo(0, 0) 对我有用

Scroll Focus Top

【讨论】:

【参考方案15】:

有同样的问题,可能是某种错误。

即使来自其他答案的fullScroll(ScrollView.FOCUS_UP) 也不起作用。 唯一对我有用的是在显示对话框后立即调用scroll_view.smoothScrollTo(0,0)

【讨论】:

这最初是可行的,但后来当我一次又一次地尝试这样做时,这种方法并没有给出令人满意的结果。 我从 scroll_view.smoothScrollTo(0,0) 解决,当我们在滚动视图旁边有 listview 时 fullScroll(ScrollView.FOCUS_UP) 将不起作用。 scroll_view.smoothScrollTo(0,0) 对我来说比 mainScrollView.fullScroll(ScrollView.FOCUS_UP);谢谢! 在大多数设备上 fullScroll(ScrollView.FOCUS_UP) 工作,但在 Nexus 5 和我的文本大小调高的设备上 - fullSscroll 在操作栏下移动,smoothScrollTo(0,0) 工作在所有设备上都更好。 这也比fullScroll() 具有优势,因为它在移动后保持所选项目仍然处于选中状态。使用fullScroll(),在我的情况下,每次都会重新选择滚动视图中的第一项,与滚动向上移动之前的选定项目无关。

以上是关于如何滚动到长 ScrollView 布局的顶部?的主要内容,如果未能解决你的问题,请参考以下文章

如何在屏幕顶部修复布局

检查 ScrollView 是不是已到达布局的顶部

如何以编程方式将 ScrollView 滚动到底部

在自动布局的情况下,IOS scrollview 模糊的可滚动内容高度

使 UIScrollView 中的顶部图像在滚动视图边界上放大?

android 自定义scrollview 仿QQ空间效果 下拉伸缩顶部图片,上拉回弹 上拉滚动顶部title 颜色渐变