21

我在 ScrollView 中嵌入 ListView 时遇到了问题,或者至少我猜这就是问题所在。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>   

但是,当我在 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> 

如果 ListView 的高度设置为“wrap_content”,则仅显示第一个元素。这就是为什么我使用一种方法来计算列表行的高度:

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;
        }
    }

不幸的是,如果 TextView 中的文本被换行,即使是多行,getMeasuredHeight() 方法返回的行元素的高度也是恒定的。即使文本被换行,在行元素内的 TextView 上调用的 getLineCount() 也会返回 1。

另一方面,如果此 ListView 嵌入在 LinearLayout 中,则一切正常,并且显示完整列表而没有剪辑。

您对这里可能出现的问题有什么建议吗?我真的不喜欢手动测量列表元素高度的想法,它显然不起作用,但为什么 android 不能很好地拉伸 ScrollView 内的 ListView 以适应它呢?

剪辑清单: 看图片

4

10 回答 10

40

使用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);
    }
于 2013-04-19T11:55:16.047 回答
11

封装在 a 中是一种不好的做法,因为 ListView 本身包含滚动功能。您应该实现一个不包含这种视图层次结构的解决方案,我希望它能发挥作用:)ListViewScrollView

于 2012-05-22T20:12:56.577 回答
2

我的项目中遇到了同样的问题。您需要在 ScrollView 中创建简单的 LinearLayout。之后,您需要使用LayoutInflater使用列表视图项 xml创建新视图。创建后将所有数据放入新视图并添加到 LinearLayout 作为子视图

linearLayot.addView(newView, position_you_need).

希望对你有帮助!

于 2012-05-23T06:43:58.357 回答
2

这里是带有 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>

这里是插入项目的代码:

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);

}       
于 2012-05-24T04:26:55.747 回答
1

我将不使用 ScrollView 中的 ListView 元素的建议牢记在心,并决定使用稍微蛮力的方法来实现我所需要的。由于需要显示的列表行数是恒定的,因此我从 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" />

在 Activity 类中,我为这些视图声明了五个占位符:

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

并初始化它们:

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);

然后,每当收到新消息时,我都会使用 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);
    }   
  }
}

我不会再膨胀 pariculat 视图,因为唯一改变的是每一行的内容,而不是布局。这意味着这里没有性能损失。

这基本上是具有有限最大元素数量的 ListView 的手动实现。然而,这一次,ScrollView 能够很好地适应它们,并且没有任何东西被剪裁。

对于动态行数,Layko 建议的方法可以用于以编程方式实例化视图并添加到 ScrollView 内的 LinearLayout。

于 2012-05-23T10:59:51.793 回答
0

我可以看到 ListView 在 ViewPager 中;解决此问题的另一种简单方法是添加 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"/>

为了防止列表底部出现相同的行为,您还可以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"/>

这来晚了,但我希望它可以帮助任何其他人。

于 2017-03-23T11:07:10.757 回答
0

试试看.. 创建所有视图后,为屏幕上的 ScrollView 位置添加波纹管(x,y)

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

  scrollView.smoothScrollTo(0,0);// top location zero index
于 2017-05-08T08:35:01.430 回答
0

我有一个类似的问题。我有一个

RelativeLayout
  listView
  includeLayout  

我在列表视图下方包含一些底部导航

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

并且我的 listView 被剪裁了 - 没有占用标题和底部导航之间可用的全部高度。我尝试了此线程和其他线程中建议的各种 xml 设置,但对我有用的是添加

android:layout_alignBottom="@+id/includeLayout"

到我的列表视图。这似乎将 listView 拉到底部导航的顶部,以便 listView 现在使用完整的可用高度(并根据需要滚动)。

于 2017-05-10T13:05:55.247 回答
0

这对我有用

<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>
于 2017-11-16T03:59:24.097 回答
0

这是不好的做法。但是在某些情况下我们无法避免使用它。例如动态电子商务布局,我们可能会放置多个列表或回收视图,但您不想在单个项目高度内滚动(如果不小心想要!!)。我遇到了这种问题。我用一种简单的方法修复了。我不说这是正确的方法,但它可能会有所帮助。!!我曾经回收视图。

(01) 创建一个返回视图高度的接口。

public interface AfterViewLoadListener {

    void onViewHeightMeasured(int height, String mode);
}

(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) 内部循环视图自定义适配器

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

(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) 就是这样。它对我有用。

于 2020-03-18T17:14:33.183 回答