简体   繁体   English

滚动视图中的ListView我的滚动视图移到列表视图的顶部。 我该如何预防?

[英]ListView in Scroll View my scrollview moves to top of listview. How do I prevent this?

I have a listview in my scroll view underneath almost a page worth of scroll before that but once my listview gets populated the scrollview moves to the top of the list view. 在此之前,我的滚动视图下面几乎有一个值得滚动的页面,下面有一个列表视图,但是一旦填充了列表视图,滚动视图就会移到列表视图的顶部。 how can I fix this/prevent this from happening? 我该如何解决/防止这种情况发生?

SCROLL VIEW XML: 滚动查看XML:

<ScrollView
    android:id="@+id/tvscrollview"
    android:layout_marginTop="8.0dip" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <include 
            layout="@layout/a" />

        <include 
            layout="@layout/b" />

        <include 
            layout="@layout/c" />

        <include 
            layout="@layout/d" />


<ListView
    android:id="@+id/listview"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />

    </LinearLayout>
</ScrollView>

I've tried doing sv.fullScroll(ScrollView.FOCUS_UP); 我试着做sv.fullScroll(ScrollView.FOCUS_UP); and all that stuff to my scrollview but it doesnt work 和所有这些东西到我的scrollview,但它不起作用

We should never put a ListView inside a ScrollView . 我们永远不要将ListView放在ScrollView

Work Around : When ScrollView moves up/down because of listview's notifyDataSetChanged() , Then try, 解决方法:当ScrollView由于listview的notifyDataSetChanged()而向上/向下移动时,请尝试,

scrollview.setEnabled(false);
listview.setFocusable(false);
adapter.notifyDataSetChanged();
scrollview.setEnabled(true);

Firstly, probably you've already heard about it, but just in case: You should never put a ListView inside a ScrollView , as ListView itself already has got a ScrollView and this design goes against the whole ListView idea. 首先,您可能已经听说过它,但以防万一: 您永远不应该将ListView放在ScrollView ,因为ListView本身已经拥有ScrollView且此设计与整个ListView想法ListView If you're convinced you have to use it, probably there's a better approach to use and you may need to simplify your code somehow. 如果您确信必须使用它,则可能有更好的使用方法,并且可能需要以某种方式简化代码。

Now, even if you still want to use something like that, you may use something like this: 现在,即使您仍想使用类似的东西,也可以使用类似的东西:

package your.package.name;

import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.ListView;

public class ScrollingListView {
  public static void setListViewHeightBasedOnChildren(ListView listView) {
    ListAdapter listAdapter = listView.getAdapter(); 
    if (listAdapter == null)
      return;

    int totalHeight = 0;
    for (int i = 0; i < listAdapter.getCount(); i++) {
      View listItem = listAdapter.getView(i, null, listView);
      listItem.measure(0, 0);
      totalHeight += listItem.getMeasuredHeight();
    }

    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
    listView.setLayoutParams(params);
  }
}

You simply set your adapter via .setAdapter() and afterwards call ScrollingListView.setListViewHeightBasedOnChildren(your_listview) . 您只需通过.setAdapter()设置适配器,然后调用ScrollingListView.setListViewHeightBasedOnChildren(your_listview) This should redimension your window accordingly to your ListView height. 这应该根据您的ListView高度重新定义窗口。

---- EDIT ---- ----编辑----

That will be probably the ugliest workaround, but try doing the following: 这可能是最丑陋的解决方法,但是请尝试执行以下操作:

ScrollView sv = (ScrollView) findViewById(R.id.your_scrollview);
sv.setEnabled(false);
// Populate your ListView
sv.setEnabled(true);

Just Do one thing before add items in your list 在将项目添加到列表中之前只需做一件事

listview.setFocusable(false);

after that you can again do that 之后,您可以再次执行该操作

listview.setFocusable(true);

if needed it will work for sure 如果需要的话,可以肯定的工作

It's not possible to make a scrollable view inside a scrollable view. 无法在可滚动视图中创建可滚动视图。 But as a work around this, and only in case that this listviews doesn't take much memory if all views are loaded. 但是,作为一种解决方法,并且仅在所有列表均已加载的情况下,此列表视图不会占用太多内存的情况下,才可以解决此问题。 you can use this 你可以用这个

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;

public class NonScrollableListView extends ListView {
    public NonScrollableListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Do not use the highest two bits of Integer.MAX_VALUE because they are
        // reserved for the MeasureSpec mode
        int heightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, heightSpec);
        getLayoutParams().height = getMeasuredHeight();
    }

}

Again, it's not good to use this workaround 同样,使用此替代方法不是很好

Add all the stuff on top as header to the list view. 将顶部的所有内容添加为列表视图的标题

Now that I see the code.. you can only have one ViewGroup inside a scrollview. 现在,我看到了代码..您在滚动视图中只能有一个ViewGroup。 So you would warp the two layouts into another one, BUT a ListView automatically has a scroll view in it so that wont really work. 因此,您需要将这两种布局扭曲到另一种布局中,但是ListView会自动在其中包含一个滚动视图,这样就不会真正起作用。

So what you have to do is use the addHeader view in your ListActivity (of fragment) and inflate LinearLayout1 in the activity from a different xml file. 因此,您要做的是在ListActivity(片段的)中使用addHeader视图,并从不同的xml文件为活动中的LinearLayout1充气。

add: 加:

android:transcriptMode="disabled"

in the list you don't want to scroll 在您不想滚动的列表中

From Android Docs 从Android文档

I would wrap the list and the other layouts in a RelativeLayout instead of a LinearLayout 我将列表和其他布局包装在RelativeLayout而不是LinearLayout

<ScrollView
    android:id="@+id/tvscrollview"
    android:layout_marginTop="8.0dip" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <RelativeLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <LinearLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

            <include 
                layout="@layout/a" />

            <include 
                layout="@layout/b" />

            <include 
                layout="@layout/c" />

            <include 
                layout="@layout/d" />

        </LinearLayout>

        <ListView
            android:id="@+id/listview"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/container" />

    </RelativeLayout>
</ScrollView>

This way the top border of the ListView is boun to the bottom border of the LinearLayout and will always stay under everything else. 这样, ListView的顶部边界将一直延伸到LinearLayout的底部边界,并且将始终停留在其他所有区域之下。

You cant put the includes directly in the RelativeLayout ! 您不能将include直接放在RelativeLayout See here for more details. 有关更多详细信息,请参见此处

I have made 2 or 3 changes in your xml file 我在您的xml文件中进行了2或3次更改

<ScrollView
    android:id="@+id/tvscrollview"
    android:layout_marginTop="8.0dip" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" 
        android:padding="10dp">  // This will let you see the scroll bar of list view
                                    when you scroll your list view.

        <include 
            layout="@layout/a" />
        <include 
            layout="@layout/b" />
        <include 
            layout="@layout/c" />
        <include 
            layout="@layout/d" />


    <ListView
    android:id="@+id/listview"
    android:layout_width="fill_parent"
    android:layout_height="300dp" />// Instead of wraping up your list, if you wish
                                       you can give certain height to your list view.

    </LinearLayout>
</ScrollView>

Another thing you need is write the given code in your java file. 您需要做的另一件事是在Java文件中编写给定的代码。

   onCreate()
  {
   ....
   ScrollView sView=(ScrollView)findViewById(R.id.tvscrollview);

   yourListView.setOnTouchListener(new OnTouchListener()
    {
        public boolean onTouch(View arg0, MotionEvent arg1) 
        {
            if(arg1.getAction() == MotionEvent.ACTION_DOWN ||   arg1.getAction() == MotionEvent.ACTION_MOVE)
            {
                sView.requestDisallowInterceptTouchEvent(true);
            }
            return false;
        }
    });

I hope this helps you. 我希望这可以帮助你。

You may want to achieve this by using following: 您可能想通过使用以下方法实现此目的:

 <LinearLayout 
......>
<ScrollView
    android:id="@+id/tvscrollview"
    android:layout_marginTop="8.0dip" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <include 
            layout="@layout/a" />

        <include 
            layout="@layout/b" />

        <include 
            layout="@layout/c" />

        <include 
            layout="@layout/d" />

    </LinearLayout>
</ScrollView>
<ListView
    android:id="@+id/listview"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
 </LinearLayout>

Wrap your listview outside scrollview and else inside scrollview, because You should never use a ScrollView with a ListView, because ListView takes care of its own vertical scrolling. 将listview包装在scrollview外部,然后将其包装在scrollview内部,因为您永远不应该将ScrollView与ListView一起使用,因为ListView负责其自身的垂直滚动。 Most importantly, doing this defeats all of the important optimizations in ListView for dealing with large lists, since it effectively forces the ListView to display its entire list of items to fill up the infinite container supplied by ScrollView. 最重要的是,这样做会挫败ListView中处理大型列表的所有重要优化,因为它有效地迫使ListView显示其整个项目列表,以填充ScrollView提供的无限容器。

Source Android Docs 来源Android文档

The only solution that worked for me was to add an EditText as the first child of the layout. 对我而言唯一有效的解决方案是将EditText添加为布局的第一个子项。 Ugly, I know. 丑,我知道。

<EditText
  android:layout_width="0dp"
  android:layout_height="0dp" />

I had the same issue I found the solution by changing the visibility of the list view in XML after setting the adapter I change the visibility to visible 我有一个相同的问题,我发现了解决方案,方法是在设置适配器后将可见性更改为visible,从而更改XML中的列表视图的可见性

listView.setAdapter(adapter);
listView.setVisibility(View.VISIBLE);

Though its a very late answer to this question and this answer has already an accepted answer, I thought putting how I solved my problem here might help others to find everything related to this problem in a single SO thread. 尽管对这个问题的回答很晚,而且这个回答已经被接受,但我认为将解决问题的方式放在这里可能会帮助其他人在单个SO线程中找到与此问题相关的所有内容。

So here's my situation: I had a ScrollView with a ListView at the end of the layout. 所以这是我的情况:在布局的末尾有一个带有ListViewScrollView I know its a very bad practice to do so. 我知道这样做是非常不好的做法。 I could achieve the same behaviour I wanted by attaching a header to the ListView . 通过将标头附加到ListView可以实现所需的相同行为。 But anyway, my ListView got the focus when it was populated with the data and the the page was scrolled automatically to the bottom where the ListView started. 但是无论如何,当我用数据填充ListView时,它就成为焦点,并且页面自动滚动到ListView开始的底部。

I tried with the accepted answer here, but it didn't work for me. 我在这里尝试了接受的答案,但是它对我没有用。 I tried using a dummy EditText at the top of the layout so that it could request the focus automatically, but it didn't work either. 我尝试在布局的顶部使用虚拟EditText ,以便它可以自动请求焦点,但也没有用。 Because the ListView was getting the focus after the data is loaded from a REST Api call. 因为从REST Api调用加载数据后, ListView成为焦点。

Then I found this answer and this really helped. 然后我找到了这个答案 ,这确实有所帮助。 So I thought putting it in here so that others might get help from a single thread having the same problem like me. 因此,我认为将其放在此处,以便其他人可以从与我一样存在相同问题的单个线程中获得帮助。

mainScrollView.fullScroll(ScrollView.FOCUS_UP); didn't work for me either as the list was populated after the other views were populated. 这对我也不起作用,因为在填充其他视图之后填充了列表。 So I had to scroll the ScrollView to the top after the ListView is populated. 因此,在填充ListView之后,我不得不将ScrollView到顶部。 So here's how I solved my problem. 因此,这就是我解决问题的方式。

mScrollView.setEnabled(false);
mIntroducerListView.setFocusable(false);
mListAdapter.notifyDataSetChanged();

// Force scroll to the top of the scroll view.
// Because, when the list view gets loaded it focuses the list view
// automatically at the bottom of this page.
mScrollView.smoothScrollTo(0, 0);

I tried the above answers, but neither of them worked. 我尝试了上述答案,但是它们都不起作用。 Below is my final solution. 下面是我的最终解决方案。 Just override the onFinishInflate method, then do a post to scrollTo(0, 0). 只需重写onFinishInflate方法,然后将其张贴到scrollTo(0,0)。

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
        this.post(new Runnable() {
            @Override
            public void run() {
                scrollTo(0, 0);
            }
        });
}

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

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