简体   繁体   English

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

[英]How to scroll to top of long ScrollView layout?

For part of my app, the user is presented with a list of names and is asked to group them as they see fit.对于我的应用程序的一部分,用户会看到一个名称列表,并被要求按照他们认为合适的方式对它们进行分组。

(Note, the ListView code was copied verbatim from the Android Views tutorial. I haven't yet customized it to my needs, I'm just trying to figure out how to make this work.) (注意,ListView 代码是从 Android 视图教程中逐字复制的。我还没有根据我的需要对其进行定制,我只是想弄清楚如何使它工作。)

The basic layout is a LinearLayout, containing a ScrollView (called "groupsScrollView" in the code below), containing a RelativeLayout.基本布局是一个LinearLayout,包含一个ScrollView(在下面的代码中称为“groupsScrollView”),包含一个RelativeLayout。 I have some buttons and text, and then my ListView beneath that, which displays the list of names.我有一些按钮和文本,然后是下面的 ListView,它显示名称列表。 All this is taller than the visible screen area, so the user is allowed to scroll vertically to see it all.所有这些都高于可见屏幕区域,因此允许用户垂直滚动以查看所有内容。

This all works beautifully, except when the page loads it is always pre-scrolled to the top of my ListView - in the middle of the page.这一切都很好,除了页面加载时它总是预先滚动到我的 ListView 的顶部 - 在页面的中间。 The text and buttons I've created that tell the user what to do are not visible.我创建的告诉用户该做什么的文本和按钮是不可见的。

I can grab the screen and scroll up, that works just fine, but I'd like the screen to load having already been scrolled to the top.我可以抓住屏幕并向上滚动,效果很好,但我希望屏幕加载已经滚动到顶部。 The user shouldn't have to scroll UP to see the top of a freshly loaded page.用户不必向上滚动即可看到新加载页面的顶部。 But everything I've tried to programmatically scroll to the top of the screen has failed.但是我试图以编程方式滚动到屏幕顶部的一切都失败了。

Here's my onCreate method:这是我的 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();
        }
      });
}

The line "mainScrollView.pageScroll(View.FOCUS_UP); is the problem. It doesn't cause an error, but it doesn't seem to do anything. I've tried scrollTo(0,0), scrollDirection(View.FOCUS_UP), and everything else I can think of. “mainScrollView.pageScroll(View.FOCUS_UP); 行是问题所在。它不会导致错误,但似乎没有做任何事情。我试过 scrollTo(0,0), scrollDirection(View.FOCUS_UP ),以及我能想到的一切。

Since I don't get an error I have to assume that these scroll commands are actually working, but that they're scrolling to the top of the ListView, rather than the top of the ScrollView or RelativeLayout that contains it.由于我没有收到错误,我必须假设这些滚动命令实际上正在工作,但它们正在滚动到 ListView 的顶部,而不是包含它的 ScrollView 或 RelativeLayout 的顶部。 This seems to be confirmed by Google's own description of the scrollTo(int x, int y) method where they say "This version also clamps the scrolling to the bounds of our child.".谷歌自己对 scrollTo(int x, int y) 方法的描述似乎证实了这一点,他们说“这个版本还将滚动限制在我们孩子的范围内。”。

So to make a long question even longer, how do I load a bunch of views on the screen contained within a ScrollView, and then programmatically scroll the whole thing to the top of the page so the user can interact with it?因此,要提出一个更长的问题,如何在 ScrollView 中包含的屏幕上加载一堆视图,然后以编程方式将整个内容滚动到页面顶部,以便用户可以与之交互?

Thanks!谢谢!

Try尝试

mainScrollView.fullScroll(ScrollView.FOCUS_UP);

it should work.它应该工作。

Had the same issue, probably some kind of bug.有同样的问题,可能是某种错误。

Even the fullScroll(ScrollView.FOCUS_UP) from the other answer didn't work.甚至来自另一个答案的fullScroll(ScrollView.FOCUS_UP)也不起作用。
Only thing that worked for me was calling scroll_view.smoothScrollTo(0,0) right after the dialog is shown.唯一对我scroll_view.smoothScrollTo(0,0)的是在显示对话框后立即调用scroll_view.smoothScrollTo(0,0)

i had the same problem and this fixed it.我有同样的问题,这解决了它。 Hope it helps you.希望对你有帮助。

listView.setFocusable(false);

scrollViewObject.fullScroll(ScrollView.FOCUS_UP) this works fine, but only the problem with this line is that, when data is populating in scrollViewObject, has been called immediately. scrollViewObject.fullScroll(ScrollView.FOCUS_UP)这工作正常,但这一行的唯一问题是,当数据在 scrollViewObject 中填充时,已被立即调用。 You have to wait for some milliseconds until data is populated.您必须等待几毫秒才能填充数据。 Try this code:试试这个代码:

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

OR或者

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

The main problem to all these valid solutions is that you are trying to move up the scroll when it isn't drawn on screen yet.所有这些有效解决方案的主要问题是,当滚动尚未绘制在屏幕上时,您正试图向上移动滚动。

You need to wait until scroll view is on screen, then move it to up with any of these solutions.您需要等到滚动视图出现在屏幕上,然后使用这些解决方案中的任何一个将其向上移动。 This is better solution than a postdelay, because you don't mind about the delay.这是比后延迟更好的解决方案,因为您不介意延迟。

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

Very easy好简单

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

I faced Same Problem When i am using Scrollview inside View Flipper or Dialog that case scrollViewObject.fullScroll(ScrollView.FOCUS_UP) returns false so that case scrollViewObject.smoothScrollTo(0, 0) is Worked for me我面临着同样的问题,当我使用滚动视图查看翻转或对话框内这种情况下scrollViewObject.fullScroll(ScrollView.FOCUS_UP)这样的情况下返回false scrollViewObject.smoothScrollTo(0, 0)是为我工作

Scroll Focus Top 滚动焦点顶部

 final ScrollView scrollview = (ScrollView)findViewById(R.id.selected_place_layout_scrollview);

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

这对我有用

scroll_view.smoothScrollTo(0,0); // scroll to top of screen
runOnUiThread( new Runnable(){
   @Override
   public void run(){
      mainScrollView.fullScroll(ScrollView.FOCUS_UP);
   }
}

I fixed my issue in Kotlin like this:我在 Kotlin 中解决了我的问题,如下所示:

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

You can also create an extension of this like:您还可以创建这样的扩展:

ScrollView.moveToTop()
{
    this.isFocusableInTouchMode = true
    this.fullScroll(View.FOCUS_UP)
    this.smoothScrollTo(0,0)
}

and use it like:并使用它:

scrollView.moveToTop()

This is force scroll for scrollview :这是滚动视图的强制滚动:

            scrollView.post(new Runnable() {
                @Override
                public void run() {
                    scrollView.scrollTo(0, 0);
                    scrollView.pageScroll(View.FOCUS_UP);
                    scrollView.smoothScrollTo(0,0);
                }
            });
scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        // Ready, move up
        scrollView.fullScroll(View.FOCUS_UP);
    }
});

This solution also works for NestedScrollView此解决方案也适用于 NestedScrollView

NestedScrollView nestedScrollView = view.findViewById(R.id.YourNestedScrollViewID);
nestedScrollView.fullScroll(ScrollView.FOCUS_UP);
@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);
    }

A few years later, the only proper solution is a mix of this thread:几年后,唯一合适的解决方案是混合这个线程:

  • without a listener or a post delayed handler, simpler solutions will fail because the can try to scroll before the ScrollView is drawn on the screen like explained by @Pelanes如果没有侦听器或延迟后处理程序,更简单的解决方案将失败,因为可以尝试在 ScrollView 绘制在屏幕上之前滚动,就像@Pelanes 解释的那样
  • the most proposed answer scan_settings_sv.fullScroll(View.FOCUS_UP);最推荐的答案scan_settings_sv.fullScroll(View.FOCUS_UP); will move view to the first focusable element, not necessarily the top of scroll view.将视图移动到第一个可聚焦元素,不一定是滚动视图的顶部。 So, if there is a header or some text, or disabled views greyed out, and and a TextView below them, the ScrollView will move up to the TextView and not ScrollView Header因此,如果有标题或某些文本,或者禁用的视图灰显,并且它们下方有一个 TextView,则 ScrollView 将向上移动到 TextView 而不是 ScrollView Header
  • Like @Nilhcem commented, we need to remove the listener at the end, else the ScrollView will keep moving up就像@Nilhcem 评论的那样,我们需要在最后删除监听器,否则 ScrollView 将继续向上移动
  • I also implemented it with the global OnGlobalLayoutListener reference as method argument to fix compiler warnings我还使用全局OnGlobalLayoutListener引用作为修复编译器警告的方法参数来实现它

So, the final solution should implement view.smoothScrollTo(0,0);所以,最终的解决方案应该是实现view.smoothScrollTo(0,0); , combined with OnGlobalLayoutListener to ensure the view was properly drwan on screen: ,结合OnGlobalLayoutListener确保视图在屏幕上正确显示:

final ScrollView my_view= dialog.findViewById(R.id.my_view_id);
scan_settings_sv.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        // Ready, move up
        //my_view.fullScroll(View.FOCUS_UP); //moves up to the to selectable/focusable element
        my_view.smoothScrollTo(0,0); // scrolls to top of view
        my_view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }
});

Note that it is very important to get the ScrollView just before invoking the method!请注意,在调用方法之前获取 ScrollView 非常重要! Else, if the view height changed after the first final ScrollView my_view= dialog.findViewById(R.id.my_view_id);否则,如果在第一个final ScrollView my_view= dialog.findViewById(R.id.my_view_id); invocation, for example because a ListView below the ScrollView was expanded, the scroll will not properly reach top of the ScrollView调用,例如因为 ScrollView 下方的 ListView 已展开,滚动将无法正确到达 ScrollView 的顶部

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM