web-dev-qa-db-ja.com

Android ScrollViewのListView行が完全に表示されない-クリップ

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をうまく拡大できないのですか?そこで?

クリップされたリスト: see image

21
PawelPredki

ListView自体にスクロール機能が含まれているため、ListViewScrollView内にカプセル化するのは[〜#〜] bad [〜#〜]プラクティスです。このようなビューの階層を含まないソリューションを実装する必要があります。それが魔法のように機能することを願っています:)

11
waqaslam

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);
    }
40
Rajesh Wadhwa

私のプロジェクトでも同じ問題が発生しました。ScrollView内の単純なLinearLayoutを作成する必要があります。その後新しいビューを作成する必要がありますyour listview item xmlLayoutInflaterを使用します。作成後、すべてのデータを新しいビューに追加し、子ビューとしてLinearLayoutに追加

linearLayot.addView(newView, position_you_need).

それがあなたを助けることを願っています!

2
Layko Andrey

ここでは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);

}       
2
Layko Andrey

私はScrollView内でListView要素を使用しないことを推奨し、必要なことを達成するために少し力ずくの方法を使用することにしました。表示する必要がある最大5つのリスト行の定数があるので、ListViewのインスタンス化をxmlファイルから削除し、それを行の5つのインスタンスで置き換えました。

<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クラスでは、これらのビューの5つのプレースホルダーを宣言します。

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に追加できます。

1
PawelPredki

これは私のために働く

<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>
0
Nouman Ch

それを試してください..すべてのビューを作成した後、画面上のScrollViewの場所(x、y)に以下の行を追加します

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

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

ListViewがViewPager内にあることがわかります。この問題を解決するもう1つの簡単な方法は、以下に示すように、レイアウトxmlのViewPagerにapp:layout_behavior="@string/appbar_scrolling_view_behavior"を追加することです。

<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"/>

これは遅くなりますが、他の人の役に立つことを願っています。

0
Cletus Ajibade

同様の問題がありました。私は

RelativeLayout
  listView
  includeLayout  

これでlistViewの下にいくつかの下部ナビゲーションを含めます

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

そして私のリストビューは切り取られました-ヘッダーと下部ナビゲーションの間で利用可能な高さ全体をとっていません。私はこのスレッドや他のスレッドで提案されているさまざまなxml設定を試しましたが、私のために働いたのは追加することでした

Android:layout_alignBottom="@+id/includeLayout"

私のlistViewに。これにより、listViewが下部ナビゲーションの上部に引き下げられたように見えたため、listViewは使用可能な高さ全体を使用しています(必要に応じてスクロールします)。

0
John Leasia

これは悪い習慣です。しかし、そこにはare使用を避けられない状況があります。たとえば、動的なeコマースレイアウトの場合、複数のリストを配置したり、ビューをリサイクルしたりできますが、1つのアイテムの高さの内側をスクロールしたくない場合(誤って必要な場合)。このような問題に直面しました。簡単な方法で修正しました。私はこれが正しい方法だとは言いませんが、いくつかを助けるかもしれません。 !!以前はビューをリサイクルしていました。

(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)以上です。それは私のために働いた。