放入自定义ViewGroup时,RecyclerView不会滚动

时间:2018-07-08 11:24:29

标签: android android-recyclerview viewgroup

为什么当我的RecyclerView放入自定义ViewGroup布局时不会滚动?

我创建了一个名为StripedLayout的自定义ViewGroup

/**
 * A Layout that lays out child view horrizontally and makes them
 * take up a prescribed % of the width of the screen .
 */
@SuppressWarnings("CanBeFinal")
@RemoteViews.RemoteView
public class StripedLayout extends  ViewGroup
{

    private static final String TAG ="StripedLayout";
    /** The width we want to set for each child element as a proportion of the screen width*/
    private ArrayList<Integer> mSectionsFromLeftToRightPercent;
    private Integer mDividerWidth = 16;

    /**for drawing dividing lines between screen elements*/
    private Paint mPaint;

    /**For holding information about the display*/
    private DisplayMetrics mDisplayMetrics = new DisplayMetrics();

    /**The gravity that we will use equivalent to xml android:layout_gravity="fill_vertical|center_horizontal"*/
    private static final Integer GRAVITY = 113;

    /** These are used for computing child frames based on their gravity. */
    private final Rect mTmpContainerRect = new Rect();
    private final Rect mTmpChildRect = new Rect();

    public StripedLayout(Context context)
    {
        super(context);
        setWillNotDraw(false);
        setVerticalScrollBarEnabled(true);
        getPaint();
        setScrollContainer(true);
        mSectionsFromLeftToRightPercent = new ArrayList<>();
    }

    public StripedLayout(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
        setWillNotDraw(false);
        setVerticalScrollBarEnabled(true);
        getPaint();
        mSectionsFromLeftToRightPercent = new ArrayList<>();
    }


    public StripedLayout(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
        setWillNotDraw(false);
        setVerticalScrollBarEnabled(true);
        getPaint();
        mSectionsFromLeftToRightPercent = new ArrayList<>();
        Integer dividerWidth = mDividerWidth;
        /*get Layout Params*/
        // Pull the layout param values from the layout XML during
        // inflation.  This is not needed if you don't care about
        // changing the layout behavior in XML.
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.StripedLayout );
        dividerWidth = a.getDimensionPixelSize(R.styleable.StripedLayout_divider_width, dividerWidth);
        mDividerWidth = dividerWidth;
        Integer paintColour = a.getColor(R.styleable.StripedLayout_divider_colour, getResources().getColor(android.R.color.black));
        getPaint(paintColour);
        a.recycle();
    }

    /** get the default paint colour**/
    private void getPaint()
    {
            //Paint the divider the default colour but do this only once
            if(mPaint == null)
            {mPaint = new Paint(getResources().getColor(android.R.color.black));}
    }

    //Change the paint from the default colour to another colour
    private void getPaint(Integer colour)
    {mPaint.setColor(colour);}

    /**
     * Any layout manager that doesn't scroll will want this.
     */
    @Override
    public boolean shouldDelayChildPressedState()
    {return false;}

    /**
     * Ask all children to measure themselves and compute the measurement of this
     * layout based on the children.
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        //get the display height and width
        Display display = getDisplay();
        display.getMetrics(mDisplayMetrics);
        int widthInPixels = mDisplayMetrics.widthPixels;
        //get the height of the screen
        Integer screenHeight = mDisplayMetrics.heightPixels;
        // Report our final dimensions.
        setMeasuredDimension(widthInPixels, screenHeight);
        Log.d(TAG, "onMeasure");
        //get Attributes
        Integer screenUsedPercentage =0;
        final int childCount = getChildCount();
            for (int childNumber = 0; childNumber < childCount; childNumber++)
            {
                final View child = getChildAt(childNumber);
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                Integer previousPercentageInPixels = 0;
                    if(childNumber >0)
                    {previousPercentageInPixels = mSectionsFromLeftToRightPercent.get(childNumber -1);}
                //Determine the size for each segment
                Integer nextPercentageInPixels = (widthInPixels /100) * lp.percentage;
                 //keep use of the percentage of the screen that is being used
                screenUsedPercentage += lp.percentage;
                Integer nextScreenPercentage = previousPercentageInPixels + nextPercentageInPixels;
                mSectionsFromLeftToRightPercent.add(childNumber,nextScreenPercentage);
                //round up the last measurement so that the last divider is not displayed
                if(screenUsedPercentage >= 95)
                {mSectionsFromLeftToRightPercent.add(childNumber,widthInPixels);}
            }

    }

    /**
     * Draws vertical lines on the canvas in order to partition
     * the canvas into sections
     * NOTE Each line exists on the left hand side of each section and
     * takes up room on the left hand side
     * @param canvas the canvas on which the dividers are drawn
     */
    @Override
    protected void onDraw(Canvas canvas)
    {
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++)
        {
            final View child = getChildAt(i);
            if (child != null && child.getVisibility() != GONE)
            {
                Integer left = mSectionsFromLeftToRightPercent.get(i);
                Integer right = left + mDividerWidth;
                Integer top = getPaddingTop();
                Integer bottom = getHeight();
                canvas.drawRect(left, top, right, bottom, mPaint);
            }
        }
        Log.d(TAG, "onDraw");
    }

    /**
     * Position all children within this layout.
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    {
        final int childCount = getChildCount();

      Integer currentLeftBoundary =0;

        for (int childNumber = 0; childNumber < childCount; childNumber++)
        {
            final View child = getChildAt(childNumber);
            if (child.getVisibility() != GONE)
            {
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                final int width = mSectionsFromLeftToRightPercent.get(childNumber) - currentLeftBoundary;
                final int height = child.getMeasuredHeight();
                //Measure the child so that it takes up all the room required
                child.measure(width, height);
                child.computeScroll();
                child.setScrollContainer(true);
                //allow space for divider
                child.setPadding(Math.max(child.getPaddingLeft(), mDividerWidth) ,child.getPaddingTop(),Math.max(child.getPaddingRight(), mDividerWidth),child.getPaddingBottom());
                // Compute the frame in which we are placing this child.
                mTmpContainerRect.left = currentLeftBoundary + getLeftMargin(lp.leftMargin, childNumber);
                mTmpContainerRect.right = mSectionsFromLeftToRightPercent.get(childNumber); //getRightMargin(lp.rightMargin, childNumber, childCount );
                //fill the height of the screen
                mTmpContainerRect.top = top + lp.topMargin;
                mTmpContainerRect.bottom = bottom - lp.bottomMargin;
                //move the left boundary to the right for next time
                currentLeftBoundary =  mSectionsFromLeftToRightPercent.get(childNumber);
                // Use the child's gravity and size to determine its final
                // frame within its container.
                Gravity.apply(GRAVITY, width, height, mTmpContainerRect, mTmpChildRect);
                // Place the child.
                child.layout(mTmpChildRect.left, mTmpChildRect.top, mTmpChildRect.right, mTmpChildRect.bottom);
            }

        }

    }
/**A larger margin is required on the left hand side to account for the fact that the vertical dividing line graphic is wholly within the
 * left side of the child element and should not be concealed by the child element. The first child does not have such graphic to it's left so
 * it will not need the extra wide left margin.
 * @param margin the standard margin size
 * @param childNumber Which child is being processed
 * @return integer relating to left margin width in pixels
 */
private Integer getLeftMargin(Integer margin, Integer childNumber)
{
    //Only a normal size margin is required for the first child due to there being no graphic to the left
    if(childNumber==0)
    {return margin;}
    //We need an extra wide left margin in order to display the line divider graphics
    return margin + mDividerWidth*2;
}


// ----------------------------------------------------------------------
// The rest of the implementation is for custom per-child layout parameters.
// If you do not need these (for example you are writing a layout manager
// that does fixed positioning of its children), you can drop all of this.

@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
    return new LayoutParams(getContext(), attrs);
}

@Override
protected LayoutParams generateDefaultLayoutParams() {
    return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}

@Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
    return new LayoutParams(p);
}

@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
    return p instanceof LayoutParams;
}

/**
 * Custom per-child layout information.
 */
private static class LayoutParams extends MarginLayoutParams {
    /**
     * The gravity to apply with the View to which these layout parameters
     * are associated.
     */
    private int gravity = Gravity.TOP | Gravity.START;
    private int position = 0;
    private int percentage = 33;


    private LayoutParams(Context c, AttributeSet attrs)
    {
        super(c, attrs);

        // Pull the layout param values from the layout XML during
        // inflation.  This is not needed if you don't care about
        // changing the layout behavior in XML.
        TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.StripedLayout_Layout );
        gravity = a.getInt(R.styleable.StripedLayout_Layout_android_gravity, gravity);
        position = a.getInt(R.styleable.StripedLayout_Layout_position, position);
        percentage = a.getInt(R.styleable.StripedLayout_Layout_percentage, percentage);
        a.recycle();
    }

    private LayoutParams(int width, int height) {
        super(width, height);
    }

    private LayoutParams(ViewGroup.LayoutParams source) {
        super(source);
    }

}
}

此xml的活动使用布局

<com.blackstephen.line_wizard.common.utility.StripedLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.blackstephen.line_wizard.show.view.ActivityBoatAndLine"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:divider_width = "8dp"
app:divider_colour= "@android:color/black">

        <FrameLayout
            android:id="@+id/boat_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:percentage="40">
        </FrameLayout>

        <FrameLayout
            android:id="@+id/line_purpose_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:percentage="20">
        </FrameLayout>

        <FrameLayout
            android:id="@+id/line_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:percentage="40">
        </FrameLayout>

</com.blackstephen.line_wizard.common.utility.StripedLayout>

然后使用片段事务添加这些片段

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical"
          android:background="@color/light_theme_fragment"
          tools:context="com.blackstephen.line_wizard.show.view.FragmentSailBoat">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/light_theme_fragment_toolbar"
            android:orientation="horizontal">
               <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/button_new_boat"
                    style="?android:attr/borderlessButtonStyle"
                    android:id="@+id/btn_new_boat"/>
               <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/button_view_shopping_list"
                    style="?android:attr/borderlessButtonStyle"
                    android:id="@+id/btn_view_shopping_list"/>
               <Button
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:id="@+id/btn_recent_purchases"
                    android:textAlignment="textStart"
                    style="?android:attr/borderlessButtonStyle"
                    android:background="@color/light_theme_fragment_toolbar"
                    android:text="@string/button_recent_purchases"/>
        </LinearLayout>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text="@string/sail_boats_heading"
            tools:ignore="UnusedAttribute"/>

            <ViewSwitcher
                android:id="@+id/data_status_view_switcher_boat"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <android.support.v7.widget.RecyclerView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:tag="@string/view_switcher_recycler_view"
                    android:id="@+id/sail_boat_recycler_view">
                </android.support.v7.widget.RecyclerView>

                <include layout="@layout/empty_item_layout"/>

            </ViewSwitcher>

    </LinearLayout>

但是问题是,RecyclerView放置在StripedLayout中时将不会滚动。有人可以帮忙吗?

0 个答案:

没有答案