如何限制NestedScrollView内RecyclerView的高度

时间:2019-02-22 08:54:57

标签: java android android-recyclerview android-nestedscrollview

在当前的Android应用程序中,有一个屏幕显示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="android: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="android:windowNoTitle">true</item>
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowBackground">@android:color/white</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:windowCloseOnTouchOutside">false</item>
</style>

我聘用NestedScrollView的原因是为了使View在纵向和横向模式下均可工作。

我希望限制height中的RecyclerView

最接近的是使用下面的布局。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    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.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        tools:context=".MainActivity">

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

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

            <android.support.v7.widget.RecyclerView
                android:id="@+id/dummy_rv"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_margin="10dp"
                android:layout_marginStart="9dp"
                android:layout_marginEnd="9dp"
                android:layout_weight="1"
                android:background="@drawable/rv_border"
                android:fadingEdge="horizontal"
                android:fadingEdgeLength="10dp"
                android:padding="10dp"
                android:requiresFadingEdge="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>
    </android.support.v4.widget.NestedScrollView>
</LinearLayout>

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

如何限制RecyclerView的高度并使NestedScrollView变为wrap_content

我尝试过NestedScrollView的高度wrap_content,但这没有任何作用。

如何获得所需的UI?提前致谢!

4 个答案:

答案 0 :(得分:3)

我建议不要在您的NestedRecyclerView中添加页眉和页脚,而不是使用RecyclerView,这样可以很好地将整体内容放到我所看到的布局中。我想为您提供一个指向my answer here的链接,您可以在其中找到如何在RecyclerView中添加页脚和页眉。

因此,我建议使用headline_literaldivider创建一个视图并将其用作标题,而RadioGroupEditText和{{ 1}}将位于页脚中。让我知道您是否遇到任何问题。

我已经尝试实现自己想要的行为,并让我知道以下实现是否对您有用。我也在Github中添加了它。

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

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

希望有帮助!

答案 1 :(得分:0)

容易

使用具有特定高度 maxHeight 属性,如果仍然无法使用,请尝试创建扩展 RecyclerView的 customrecyclerview 并使用 OnMeasure 方法覆盖高度。

答案 2 :(得分:0)

自定义回收者视图以设置ThreadingMixIn

maxHeight

n attrs.xml

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

在xml中将RecyclerView高度<declare-styleable name="MaxHeightScrollView"> <attr name="maxHeight" format="dimension" /> </declare-styleable> 和maxHeight设置为dp中的fixwidth。 RecyclerView将消耗高度wrap_content直到您设置的fixWidth,达到maxHeight后,RecyclerView将可滚动。

答案 3 :(得分:0)

如果您还需要通过制作自定义的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>

自定义NestedScrollView的示例布局:

               <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的自定义,那么它将完全按照您想要的方式工作。我希望这会有所帮助!