简体   繁体   English

ScrollView 中的 Android ListView 行未完全显示 - 已剪辑

[英]Android ListView rows in ScrollView not fully displayed - clipped

I encountered a problem when embedding a ListView inside a ScrollView, or at least that's where I guess the problem comes from.我在 ScrollView 中嵌入 ListView 时遇到了问题,或者至少这是我猜问题的来源。 The ListView element is a fairly simple one: ListView 元素是一个相当简单的元素:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_root"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/general_background_list_middle" 
    android:paddingTop="4dp"
    android:paddingBottom="4dp"
    android:paddingRight="0dp"
    android:paddingLeft="0dp">

    <ImageView
        android:id="@+id/chat_friends_avatar"       
        android:layout_width="45dp"
        android:layout_height="45dp"
        android:layout_marginLeft="7dp"
        android:layout_marginRight="8dp"
        android:paddingRight="0dp" 
        android:paddingLeft="0dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/friends_icon_avatar_default"/>

    <TextView
        android:id="@+id/chat_message_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/chat_friends_avatar"
        android:layout_alignParentTop="true"
        android:layout_marginRight="35dp"
        android:maxLines="10"
        android:textSize="12dp"/>

    <TextView
        android:id="@+id/chat_friend_name"
        android:layout_width="140dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="3dp"
        style="@style/SubText"
        android:layout_toRightOf="@id/chat_friends_avatar"      
        android:layout_below="@id/chat_message_text" />

    <TextView
        android:id="@+id/chat_message_time"
        android:layout_width="80dp"
        android:layout_height="wrap_content"
        android:layout_marginRight="8dp"
        android:layout_marginTop="3dp"
        style="@style/SubText"
        android:layout_alignParentRight="true"
        android:layout_below="@id/chat_message_text" />

</RelativeLayout>   

However, when I embed a list of such elements in a ScrollView, in between some other elements, the rows are not fully displayed, they are clipped (see image below) if the text is wrapped.但是,当我在 ScrollView 中嵌入此类元素的列表时,在其他一些元素之间,行未完全显示,如果文本被换行,它们将被剪裁(见下图)。 The ListView is instantiated as follows in the ScrollView: ListView在ScrollView中实例化如下:

<ListView
android:id="@+id/info_chat_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:cacheColorHint="@color/frame_background_color"
android:clickable="false"
android:divider="@null"
android:footerDividersEnabled="false"
android:focusable="false" >
</ListView> 

If the height of the ListView is set to "wrap_content" only the first element is shown.如果 ListView 的高度设置为“wrap_content”,则仅显示第一个元素。 That's why I'm using a method to calculate the height of the rows of the list:这就是为什么我使用一种方法来计算列表行的高度:

private int getCommentsListHeight() {
        if (mChatAdapter != null && mChatAdapter.getCount() != 0) {
            if (mChatList != null) {// && mCommentsListItemHeight == 0) {
                mCommentsListItemHeight = 0;
                for (int i = 0; i < mChatAdapter.getCount(); i++) {
                    // Get view item height
                    View viewItem = mChatAdapter
                            .getView(i, new View(OnAirActivity.this), mChatList);
                    viewItem.measure(0, 0);
                    Logger.d(LOGTAG, "View " + i + " measured height = " + viewItem.getMeasuredHeight());
                    mCommentsListItemHeight += viewItem.getMeasuredHeight();
                }
            }
            //return mChatAdapter.getCount() * mCommentsListItemHeight;
            return mCommentsListItemHeight;
        } else {
            return 0;
        }
    }

Unfortunately, in case when the text inside the TextView is wrapped, even over several lines, the height of the row element returned by the getMeasuredHeight() method is constant.不幸的是,如果 TextView 中的文本被换行,即使是多行,getMeasuredHeight() 方法返回的行元素的高度是恒定的。 Also the getLineCount() called on the TextView inside the row element returns 1 even if the text is wrapped.即使文本被换行,在行元素内的 TextView 上调用的 getLineCount() 也会返回 1。

On the other hand, if this ListView is embedded in a LinearLayout, everything works fine and the full list is displayed with no clipping.另一方面,如果此 ListView 嵌入在 LinearLayout 中,则一切正常,并且显示完整列表而不会进行剪辑。

Do you have any suggestions as to what might be wrong here?您对这里可能出现的问题有什么建议吗? I really don't like the idea of manually measuring the height of the list elements and it apparently doesn't work but why can't android nicely stretch the ListView inside the ScrollView to fit it all in there?我真的不喜欢手动测量列表元素高度的想法,它显然不起作用,但为什么 android 不能很好地拉伸 ScrollView 内的 ListView 以适应它呢?

Clipped list:剪辑清单:看图片

Use this method created by https://stackoverflow.com/users/205192/dougw使用由https://stackoverflow.com/users/205192/dougw创建的这个方法

 public static void setListViewHeightBasedOnChildren(ListView listView) {
        ListAdapter listAdapter = listView.getAdapter(); 
        if (listAdapter == null) {
            // pre-condition
            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);
    }

It's a BAD practice to encapsulate ListView within a ScrollView because ListView itself contains scrolling capabilities.这是一个不好的做法,封装ListView一个内ScrollView ,因为ListView控件本身包含滚动功能。 You should implement a solution that does not contain such hierarchy of views and I hope it will do the magic :)您应该实现一个不包含这种视图层次结构的解决方案,我希望它会发挥作用:)

I had the same problem in my project.You need to create simple LinearLayout inside ScrollView .我在我的项目中遇到了同样的问题。你需要在 ScrollView 中创建简单的 LinearLayout After that you need create new View with your listview item xml using LayoutInflater .之后,您需要使用LayoutInflater使用列表视图项 xml创建新视图 After creation put all data in new View and add to LinearLayout as child view :创建后将所有数据放在新视图中并作为子视图添加到 LinearLayout

linearLayot.addView(newView, position_you_need).

Hope it would help you!希望能帮到你!

Here resource of main layout with ScrollView:这里使用 ScrollView 的主要布局资源:

<ScrollView android:layout_height="fill_parent" android:layout_width="fill_parent">
<LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/parentLayout"/>
</ScrollView>

Here the code to insert items:这里是插入项目的代码:

parentLayout.removeAllViews();
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int i = comments.size() - 1; i >= 0; i--) {
CommentInfo comment = comments.get(i);
View view = inflater.inflate(your_resource_id, null, false);

TextView commentsContent =(TextView)view.findViewById(R.id.commentContent);
if (commentsContent != null) {
    String data = String.format("%s (by %s, %s)",  comment.getCommentText(), comment.getUserName(),
        commentsContent.setTextSize(st.getTextSize());
    commentsContent.setText(data);

}

parentLayout.addView(view, 0);

}       

I took the recommendation of not using a ListView element inside a ScrollView to heart and decided to use a slightly brute force method to achieve what I need.我采纳了在 ScrollView 中不使用 ListView 元素的建议,并决定使用稍微强力的方法来实现我所需要的。 Since there is a constant number of up to five list rows that need to be displayed I removed the ListView instantiation from the xml file and replaced it with five instances of rows:由于需要显示最多五个列表行的恒定数量,因此我从 xml 文件中删除了 ListView 实例,并将其替换为五个行实例:

<include android:id="@+id/info_comment_1" layout="@layout/chat_single_message" />
<include android:id="@+id/info_comment_2" layout="@layout/chat_single_message" />
<include android:id="@+id/info_comment_3" layout="@layout/chat_single_message" />
<include android:id="@+id/info_comment_4" layout="@layout/chat_single_message" />
<include android:id="@+id/info_comment_5" layout="@layout/chat_single_message" />

In the Activity class I declare five placeholders for these views:在 Activity 类中,我为这些视图声明了五个占位符:

private RelativeLayout mChatMessages[] = new RelativeLayout[COMMENTS_NUMBER];

and initialize them with:并用以下方法初始化它们:

mChatMessages[0] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_1);
mChatMessages[1] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_2);
mChatMessages[2] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_3);
mChatMessages[3] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_4);
mChatMessages[4] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_5);

Then, whenever a new message is received I use the ChatAdapter (the same I used for the ListView previously) and call its getView() method:然后,每当收到新消息时,我都会使用 ChatAdapter(与我之前用于 ListView 的相同)并调用其 getView() 方法:

protected void updateChatMessages() {
  int msgCount = mChatAdapter.getCount();
  for (int i = 0; i < COMMENTS_NUMBER; i++) {
    if (msgCount <= i) {
      mChatMessages[i].setVisibility(View.GONE);
    } else {
      mChatMessages[i] = (RelativeLayout) mChatAdapter.getView(i, mChatMessages[i], null); 
      mChatMessages[i].setVisibility(View.VISIBLE);
    }   
  }
}

I don't inflate the pariculat views ever again since the only thing that changes is the content of each row, not the layout.我不再膨胀 pariculat 视图,因为唯一改变的是每一行的内容,而不是布局。 This means there is no performance penalty here.这意味着这里没有性能损失。

This is basically a manual implementation of a ListView with a limited maximum number of elements.这基本上是一个 ListView 的手动实现,其元素的最大数量是有限的。 This time, however, ScrollView is able to fit them nicely and nothing gets clipped.然而,这一次 ScrollView 能够很好地适应它们并且没有任何内容被剪裁。

For a dynamic number of rows the approach suggested by Layko could be employed with the views being instantiated programatically and added to the LinearLayout inside the ScrollView.对于动态行数,可以采用 Layko 建议的方法,以编程方式实例化视图并添加到 ScrollView 内的 LinearLayout。

I can see the ListView is inside a ViewPager;我可以看到 ListView 在 ViewPager 中; one other simple approach to resolving this issue is to add app:layout_behavior="@string/appbar_scrolling_view_behavior" to the ViewPager in your layout xml as seen below.解决此问题的另一种简单方法是将app:layout_behavior="@string/appbar_scrolling_view_behavior"到布局 xml 中的 ViewPager,如下所示。

<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

To prevent the same behavior at the bottom of the list, you can also add android:layout_marginBottom="?attr/actionBarSize" to the ViewPager like so为了防止列表底部出现相同的行为,您还可以像这样将android:layout_marginBottom="?attr/actionBarSize"添加到 ViewPager

<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:layout_marginBottom="?attr/actionBarSize"/>

This is coming late, but I hope it helps any other person.这来晚了,但我希望它可以帮助任何其他人。

try it.. after create all view add bellow line for ScrollView location on screen (x,y)试试吧..创建所有视图后为屏幕上的滚动视图位置添加波纹管(x,y)

  ScrollView scrollView = (ScrollView)findViewById(R.id.scrollView);

  scrollView.smoothScrollTo(0,0);// top location zero index

I had a similar problem.我有一个类似的问题。 I have a我有一个

RelativeLayout
  listView
  includeLayout  

where I include some bottom nav beneath the listView with this我在 listView 下面包含了一些底部导航

<include
    android:id="@+id/includeLayout"
    layout="@layout/bottom_nav_bar"

and my listView was clipped - not taking the full height available between the header and bottom nav.并且我的 listView 被剪裁了 - 没有采用标题和底部导航之间的完整高度。 I tried various xml settings suggested in this and other threads, but what worked for me was to add我尝试了在这个和其他线程中建议的各种 xml 设置,但对我有用的是添加

android:layout_alignBottom="@+id/includeLayout"

to my listView.到我的列表视图。 That seemed to pull the listView down to the top of the bottom nav, so that the listView is now using the full available height (and it scrolls as needed).这似乎将 listView 拉到底部导航的顶部,以便 listView 现在使用完整的可用高度(并根据需要滚动)。

This works for me这对我有用

<RelativeLayout                                          xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:padding="@dimen/activity_vertical_margin">

    <TextView
        android:id="@+id/tv_status"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="17sp"
        android:text="@string/text_list_devices" />

    <ListView
        android:id="@+id/lv_paired"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:cacheColorHint="#00000000"
        android:layout_above="@+id/signup_t"
        android:layout_below="@id/tv_status"
        />

    <Button

        android:id="@+id/signup_t"
        style="?android:textAppearanceSmall"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:textColor="@android:color/white"
        android:layout_alignParentBottom="true"
        android:text="Print All Records"
        android:typeface="sans"
        android:layout_marginLeft="45dp"
        android:layout_marginRight="45dp"
        android:textSize="24sp"
        android:background="@drawable/selector_for_button"
        android:textStyle="bold" />
</RelativeLayout>

This is BAD practice .这是不好的做法 But there are some situations we can not avoid using that.但也我们无法避免使用一些情况。 For example dynamic e-commerce layouts we may put multiple lists or recycle views but you don't want to scroll inside a single item height (if accidentally wanted!!).例如动态电子商务布局,我们可能会放置多个列表或回收视图,但您不想在单个项目高度内滚动(如果不小心!!)。 I faced this kind of problem.我遇到了这种问题。 I fixed using a simple way.我用一种简单的方法固定。 I don't tell this is the correct way but it may help some.我不说这是正确的方法,但它可能对某些人有所帮助。 !! !! I used to recycle the view.我曾经回收视图。

(01) Create an Interface to return view height. (01) 创建一个返回视图高度的接口。

public interface AfterViewLoadListener {

    void onViewHeightMeasured(int height, String mode);
}

(02) implement with your activity (02) 实施您的活动

public class *Activity extends AppCompatActivity implements AfterViewLoadListener{
  /**  your codes **/
  final SimpleListRecycleAdapter order_adapter = new SimpleListRecycleAdapter(this,"ORDER");
}

@Override
public void onViewHeightMeasured(int height, String mode) {
    if(mode.equals("ORDER") && height > 0){
        recycleView.setMinimumHeight(height);
    }
}

(03) inside the recycle view custom adapter (03) 内回收视图自定义适配器

AfterViewLoadListener viewLoadListener = null;
public SimpleListRecycleAdapter(AfterViewLoadListener listener, String mode) {
    if(listener instanceof AfterViewLoadListener){
        viewLoadListener = listener;
    }
    this.mode = mode;
}

(04) override the onViewAttachedToWindow method (04) 重写 onViewAttachedToWindow 方法

@Override
public void onViewAttachedToWindow(@NonNull SimpleListViewHolder holder) {
    super.onViewAttachedToWindow(holder);
    View view = holder.itemView;
    view.measure(0, 0);
    this.viewMinHeight = view.getMeasuredHeight();

    if(!firstFlag){
        firstFlag = true;
        viewLoadListener.onViewHeightMeasured(this.viewMinHeight*filtered.length(),mode);
    }
}

(05) That's it. (05) 就是这样。 It worked for me.它对我有用。

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

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