有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何限制NestedScrollView中RecyclerView的高度

在我当前的Android应用程序中,我有一个屏幕显示安卓.support.v4.app.DialogFragment

DialogFragment视图包含以下UI组件

HEADING
== Sub Heading
== NestedScrollView
==== RecyclerView
==== RadioGroup
==== Spinner
==== EditText
==== Action Buttons

DialogFragment配置为全屏,使用如下样式:-

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setStyle(DialogFragment.STYLE_NO_TITLE, R.style.AppDialogTheme);
}

我的对话风格是

<!-- Define your custom dialog theme here extending from base -->
<style name="AppDialogTheme" parent="Theme.AppCompat.Light.Dialog">
    <!-- Define color properties as desired -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">#000</item>
    <item name="安卓:textColorHighlight">@color/background_url</item>
    <item name="colorAccent">@color/dark_grey</item>
    <item name="colorControlNormal">@color/colorPrimaryDark</item>
    <!-- Define window properties as desired -->
    <item name="安卓:windowNoTitle">true</item>
    <item name="安卓:windowFullscreen">true</item>
    <item name="安卓:windowBackground">@安卓:color/white</item>
    <item name="安卓:windowIsFloating">true</item>
    <item name="安卓:windowCloseOnTouchOutside">false</item>
</style>

我使用NestedScrollView的原因是View可以在纵向和横向模式下工作

我希望限制heightRecyclerView

我得到的最接近的是使用下面的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:安卓="http://schemas.安卓.com/apk/res/安卓"
    xmlns:app="http://schemas.安卓.com/apk/res-auto"
    xmlns:tools="http://schemas.安卓.com/tools"
    安卓:layout_width="match_parent"
    安卓:layout_height="wrap_content"
    安卓:orientation="vertical">

    <TextView
        安卓:id="@+id/headline_literal"
        安卓:layout_width="match_parent"
        安卓:layout_height="wrap_content"
        安卓:layout_marginTop="10dp"
        安卓:gravity="center"
        安卓:padding="10dp"
        安卓:text="Heading"
        安卓:textSize="20sp"
        安卓:textStyle="bold" />

    <View
        安卓:id="@+id/divider"
        安卓:layout_width="fill_parent"
        安卓:layout_height="2dp"
        安卓:layout_marginTop="5dp"
        安卓:background="#c0c0c0" />

    <安卓.support.v4.widget.NestedScrollView
        安卓:layout_width="match_parent"
        安卓:layout_height="0dp"
        安卓:layout_weight="1"
        tools:context=".MainActivity">

        <LinearLayout
            安卓:layout_width="match_parent"
            安卓:layout_height="wrap_content"
            安卓:weightSum="5"
            安卓:orientation="vertical">

            <TextView
                安卓:id="@+id/sub_headline_literal"
                安卓:layout_width="match_parent"
                安卓:layout_height="wrap_content"
                安卓:gravity="center"
                安卓:padding="10dp"
                安卓:text="Some long texts having a long size so that it takes multiple lines in the view to replicate the real-life app use case. This is important to have 3-4 lines this textview so that we can see if the views are being populated correctly. Hope this sentence is long enough to replicate the real-life scenario of this TextView content. Thank you."
                安卓:textSize="16sp"
                安卓:textStyle="normal" />

            <安卓.support.v7.widget.RecyclerView
                安卓:id="@+id/dummy_rv"
                安卓:layout_width="match_parent"
                安卓:layout_height="0dp"
                安卓:layout_margin="10dp"
                安卓:layout_marginStart="9dp"
                安卓:layout_marginEnd="9dp"
                安卓:layout_weight="1"
                安卓:background="@drawable/rv_border"
                安卓:fadingEdge="horizontal"
                安卓:fadingEdgeLength="10dp"
                安卓:padding="10dp"
                安卓:requiresFadingEdge="vertical" />

            <RadioGroup
                安卓:id="@+id/myRadioGroup"
                安卓:layout_width="wrap_content"
                安卓:layout_height="wrap_content"
                安卓:layout_gravity="center"
                安卓:layout_marginTop="10dp"
                安卓:checkedButton="@+id/sound">

                <RadioButton
                    安卓:id="@+id/sound"
                    安卓:layout_width="wrap_content"
                    安卓:layout_height="wrap_content"
                    安卓:text="Sound" />

                <RadioButton
                    安卓:id="@+id/vibration"
                    安卓:layout_width="wrap_content"
                    安卓:layout_height="wrap_content"
                    安卓:text="Vibration" />

                <RadioButton
                    安卓:id="@+id/silent"
                    安卓:layout_width="wrap_content"
                    安卓:layout_height="wrap_content"
                    安卓:text="Silent" />
            </RadioGroup>

            <EditText
                安卓:id="@+id/notes"
                安卓:layout_width="match_parent"
                安卓:layout_height="wrap_content"
                安卓:hint="Notes" />

            <LinearLayout
                安卓:id="@+id/buttons"
                安卓:layout_width="match_parent"
                安卓:layout_height="wrap_content"
                安卓:orientation="horizontal"
                安卓:padding="10dp">

                <TextView
                    安卓:id="@+id/cancel_button"
                    安卓:layout_width="0dp"
                    安卓:layout_height="wrap_content"
                    安卓:layout_weight="1"
                    安卓:gravity="center"
                    安卓:text="Cancel" />

                <TextView
                    安卓:id="@+id/submit_button"
                    安卓:layout_width="0dp"
                    安卓:layout_height="wrap_content"
                    安卓:layout_weight="1"
                    安卓:gravity="center"
                    安卓:text="Submit" />
            </LinearLayout>
        </LinearLayout>
    </安卓.support.v4.widget.NestedScrollView>
</LinearLayout>

通过在NestedScrollView的内部LinearLayout上使用weightSum,我可以限制Recyclerview的高度。但是NestedScrollView高度太大,超过一半的高度为空白

我如何限制我的RecyclerView的高度并使NestedScrollView达到wrap_content

我试过NestedScrollView用身高wrap_content但没有效果

如何实现所需的UI?提前谢谢


共 (3) 个答案

  1. # 1 楼答案

    如果还需要通过定制NestedScrollView来限制NestedScrollView的大小:

    public class CustomNestedScrollView extends NestedScrollView {
    
    private int maxHeight;
    private final int defaultHeight = 200;
    
    public CustomNestedScrollView(Context context) {
        super(context);
    }
    
    public CustomNestedScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        if (!isInEditMode()) {
            init(context, attrs);
        }
    }
    
    public CustomNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        if (!isInEditMode()) {
            init(context, attrs);
        }
    }
    
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public CustomNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        if (!isInEditMode()) {
            init(context, attrs);
        }
    }
    
    private void init(Context context, AttributeSet attrs) {
        if (attrs != null) {
            TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.CustomNestedScrollView);
            //200 is a defualt value
            maxHeight = styledAttrs.getDimensionPixelSize(R.styleable.CustomNestedScrollView_maxHeight, defaultHeight);
    
            styledAttrs.recycle();
        }
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
    }
    

    attr。xml

    <declare-styleable name="CustomNestedScrollView">
            <attr name="maxHeight" format="dimension" />
        </declare-styleable>
    

    自定义嵌套滚动视图的布局示例:

                   <your.package.CustomNestedScrollView 
                    android:layout_weight="1"
                    app:maxHeight="90dp"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content">
    
                    <! Child view with RecyclerView here >
    
    
                    </your.package.CustomNestedScrollView>
    

    与此定制的NestedScrollView一起,如果您应用RecyclerView的定制,那么它将完全按照您想要的方式工作。我希望这有帮助

  2. # 2 楼答案

    我建议在RecyclerView中添加一个页眉和页脚,而不是一个NestedRecyclerView,这将很好地将整个内容放置在我所看到的布局中。我想给你提供一个到my answer here的链接,在那里你可以找到如何在^{中添加页脚和页眉

    因此,我建议创建一个带有headline_literaldivider的视图,并将其用作页眉,而RadioGroupEditTextButton将位于页脚。如果你有任何问题,请告诉我

    我已经尝试自己实现您想要的行为,并告诉我以下实现是否适合您。我也在Github中添加了这个

    让我们首先声明一个适配器,用于向RecyclerView添加页眉和页脚

    import android.content.Context;
    import android.support.v7.widget.RecyclerView;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    import java.util.ArrayList;
    
    public class RecyclerViewWithHeaderFooterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    
        private static final int FOOTER_VIEW = 1;
        private static final int HEADER_VIEW = 2;
        private ArrayList<String> data; // Take any list that matches your requirement.
        private Context context;
    
        // Define a constructor
        public RecyclerViewWithHeaderFooterAdapter(Context context, ArrayList<String> data) {
            this.context = context;
            this.data = data;
        }
    
        // Define a ViewHolder for Header view
        public class HeaderViewHolder extends ViewHolder {
            public HeaderViewHolder(View itemView) {
                super(itemView);
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        // Do whatever you want on clicking the item
                    }
                });
            }
        }
    
        // Define a ViewHolder for Footer view
        public class FooterViewHolder extends ViewHolder {
            public FooterViewHolder(View itemView) {
                super(itemView);
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        // Do whatever you want on clicking the item
                    }
                });
            }
        }
    
        // Now define the ViewHolder for Normal list item
        public class NormalViewHolder extends ViewHolder {
            public NormalViewHolder(View itemView) {
                super(itemView);
    
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        // Do whatever you want on clicking the normal items
                    }
                });
            }
        }
    
        // And now in onCreateViewHolder, you have to pass the correct view
        // while populating the list item.
    
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    
            View v;
    
            if (viewType == FOOTER_VIEW) {
                v = LayoutInflater.from(context).inflate(R.layout.list_item_footer, parent, false);
                FooterViewHolder vh = new FooterViewHolder(v);
                return vh;
            } else if (viewType == HEADER_VIEW) {
                v = LayoutInflater.from(context).inflate(R.layout.list_item_header, parent, false);
                HeaderViewHolder vh = new HeaderViewHolder(v);
                return vh;
            }
    
            // Otherwise populate normal views
            v = LayoutInflater.from(context).inflate(R.layout.list_item_normal, parent, false);
            NormalViewHolder vh = new NormalViewHolder(v);
    
            return vh;
        }
    
        // Now bind the ViewHolder in onBindViewHolder
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    
            try {
                if (holder instanceof NormalViewHolder) {
                    NormalViewHolder vh = (NormalViewHolder) holder;
    
                    vh.bindView(position);
                } else if (holder instanceof FooterViewHolder) {
                    FooterViewHolder vh = (FooterViewHolder) holder;
                } else if (holder instanceof HeaderViewHolder) {
                    HeaderViewHolder vh = (HeaderViewHolder) holder;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // Now the critical part. You have return the exact item count of your list
        // I've only one footer. So I returned data.size() + 1
        // If you've multiple headers and footers, you've to return total count
        // like, headers.size() + data.size() + footers.size()
    
        @Override
        public int getItemCount() {
            if (data == null) {
                return 0;
            }
    
            if (data.size() == 0) {
                // Return 1 here to show nothing
                return 1;
            }
    
            // Add extra view to show the header view
            // Add another extra view to show the footer view
            // So there are two extra views need to be populated
            return data.size() + 2;
        }
    
        // Now define getItemViewType of your own.
        @Override
        public int getItemViewType(int position) {
            if (position == 0) {
                // This is where we'll add the header.
                return HEADER_VIEW;
            } else if (position == data.size() + 1) {
                // This is where we'll add a footer.
                return FOOTER_VIEW;
            }
    
            return super.getItemViewType(position);
        }
    
        // So you're done with adding a footer and its action on onClick.
        // Now set the default ViewHolder for NormalViewHolder
        public class ViewHolder extends RecyclerView.ViewHolder {
            // Define elements of a row here
            public ViewHolder(View itemView) {
                super(itemView);
                // Find view by ID and initialize here
            }
    
            public void bindView(int position) {
                // bindView() method to implement actions
            }
        }
    }
    

    现在让我们逐一定义布局。这里是list_item_normal.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <TextView
            android:id="@+id/normal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="10dp"
            android:text="This is a text to be displayed in each item in the RecyclerView"
            android:textSize="16sp"
            android:textStyle="normal" />
    
    </LinearLayout>
    

    list_item_footer.xml应该如下所示

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:orientation="vertical">
    
        <RadioGroup
            android:id="@+id/myRadioGroup"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginTop="10dp"
            android:checkedButton="@+id/sound">
    
            <RadioButton
                android:id="@+id/sound"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Sound" />
    
            <RadioButton
                android:id="@+id/vibration"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Vibration" />
    
            <RadioButton
                android:id="@+id/silent"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Silent" />
    
        </RadioGroup>
    
        <EditText
            android:id="@+id/notes"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Notes" />
    
        <LinearLayout
            android:id="@+id/buttons"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:padding="10dp">
    
            <TextView
                android:id="@+id/cancel_button"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:gravity="center"
                android:text="Cancel" />
    
            <TextView
                android:id="@+id/submit_button"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:gravity="center"
                android:text="Submit" />
        </LinearLayout>
    </LinearLayout>
    

    最后,list_item_header.xml应该有以下内容

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <TextView
            android:id="@+id/sub_headline_literal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="10dp"
            android:text="Some long texts having a long size so that it takes multiple lines in the view to replicate the real-life app use case. This is important to have 3-4 lines this textview so that we can see if the views are being populated correctly. Hope this sentence is long enough to replicate the real-life scenario of this TextView content. Thank you."
            android:textSize="16sp"
            android:textStyle="normal" />
    
    </LinearLayout>
    

    现在,您已经将原始布局的组件划分为多个部分。因此,主布局应该如下所示

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    
        <TextView
            android:id="@+id/headline_literal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center"
            android:padding="10dp"
            android:text="Heading"
            android:textSize="20sp"
            android:textStyle="bold" />
    
        <View
            android:id="@+id/divider"
            android:layout_width="fill_parent"
            android:layout_height="2dp"
            android:layout_marginTop="5dp"
            android:background="#c0c0c0" />
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/dummy_rv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:padding="10dp" />
    </LinearLayout>
    

    因此,我将分享一个示例Activity来运行这段代码,它将显示整体实现

    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    
    import java.util.ArrayList;
    
    public class MainActivity extends AppCompatActivity {
    
        private RecyclerView mRecyclerView;
        private ArrayList<String> data = new ArrayList<String>();
        private RecyclerViewWithHeaderFooterAdapter adapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initializeData();
            initializeRecyclerView();
        }
    
        private void initializeRecyclerView() {
            mRecyclerView = findViewById(R.id.dummy_rv);
            mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
            adapter = new RecyclerViewWithHeaderFooterAdapter(this, data);
            mRecyclerView.setAdapter(adapter);
        }
    
        private void initializeData() {
            for (int i = 0; i < 10; i++) data.add("Position :" + i);
        }
    }
    

    希望有帮助

  3. # 3 楼答案

    自定义回收器视图以设置maxHeight

    public class MaxHeightRecyclerView extends RecyclerView {
        private int mMaxHeight;
    
        public MaxHeightRecyclerView(Context context) {
            super(context);
        }
    
        public MaxHeightRecyclerView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initialize(context, attrs);
        }
    
        public MaxHeightRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initialize(context, attrs);
        }
    
        private void initialize(Context context, AttributeSet attrs) {
            TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView);
            mMaxHeight = arr.getLayoutDimension(R.styleable.MaxHeightScrollView_maxHeight, mMaxHeight);
            arr.recycle();
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            if (mMaxHeight > 0) {
                heightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxHeight, MeasureSpec.AT_MOST);
            }
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
    

    n attrs。xml

    <declare-styleable name="MaxHeightScrollView">
            <attr name="maxHeight" format="dimension" />
        </declare-styleable>
    

    在xml中设置RecyclerView heightwrap_content,在dp中设置maxHeight为fixwidth。 RecyclerView将使用height wrap_内容,直到您设置的fixWidth,在达到maxHeight后,RecyclerView将可滚动