mercredi 6 mai 2015

Centering Lines in FlowLayout

I wrote the following FlowLayout (after extensive Googling) a while ago to wrap views onto lines as necessary. Recently, I've been trying to adapt this layout such that each line is horizontally centered. I have no idea how to start on this and any help would be appreciated. I've tried adapting it based on other related questions with no success.

public class FlowLayout extends ViewGroup {

private int lineHeight;

/**
 * The number of lines used to render the flow layout content
 */
private int linesUsed;

/**
 * Constructor
 * @param context
 */
public FlowLayout(Context context) {
    super(context);
}

/**
 * Constructor
 * @param context
 * @param attrs
 */
public FlowLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

/**
 * Constructor
 * @param context
 * @param attrs
 * @param defStyle
 */
public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        return;
    }

    linesUsed = 1;
    final int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
    int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
    final int count = getChildCount();
    int calculatedLineHeight = 0;

    int xPosition = getPaddingLeft();
    int yPosition = getPaddingTop();

    int childHeightMeasureSpec;
    if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
        childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
    } else {
        childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
    }

    for (int i = 0; i < count; i++) {
        final View child = getChildAt(i);
        if (child.getVisibility() != GONE) {
            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
            child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), childHeightMeasureSpec);
            final int childWidth = child.getMeasuredWidth();
            calculatedLineHeight = Math.max(calculatedLineHeight, child.getMeasuredHeight() + lp.verticalSpacing);

            if (xPosition + childWidth > width) {
                xPosition = getPaddingLeft();
                yPosition += calculatedLineHeight;
                linesUsed++;
            }

            xPosition += childWidth + lp.horizontalSpacing;

            // Set a tag to remember which line the child is rendered on
            child.setTag(R.id.flow_layout_child_view_tag, linesUsed);
        } else {
            child.setTag(R.id.flow_layout_child_view_tag, -1);
        }
    }

    this.lineHeight = calculatedLineHeight;

    if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
        height = yPosition + calculatedLineHeight;
    } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
        if (yPosition + calculatedLineHeight < height) {
            height = yPosition + calculatedLineHeight;
        }
    }
    setMeasuredDimension(width, height);
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    final int count = getChildCount();
    final int width = r - l;
    int xPosition = getPaddingLeft();
    int yPosition = getPaddingTop();

    for (int i = 0; i < count; i++) {
        final View child = getChildAt(i);
        if (child.getVisibility() != GONE) {
            final int childWidth = child.getMeasuredWidth();
            final int childHeight = child.getMeasuredHeight();
            final LayoutParams lp = (LayoutParams) child.getLayoutParams();

            if (xPosition + childWidth > width) {
                xPosition = getPaddingLeft();
                yPosition += lineHeight;
            }
            child.layout(xPosition, yPosition, xPosition + childWidth, yPosition + childHeight);
            xPosition += childWidth + lp.horizontalSpacing;
        }
    }
}

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

@Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
    return new LayoutParams(1, 1); // default of 1px spacing
}

/**
 * Returns the total number of lines used to render the contents of the flow layout
 */
public int getTotalLines() {
    return linesUsed;
}

/** Per-child layout information associated with FlowLayout. */
public static class LayoutParams extends ViewGroup.LayoutParams {

    private final int horizontalSpacing;
    private final int verticalSpacing;

    /**
     * Constructor
     *
     * @param horizontalSpacing Pixels between items, horizontally
     * @param verticalSpacing Pixels between items, vertically
     */
    public LayoutParams(int horizontalSpacing, int verticalSpacing) {
        super(0, 0);
        this.horizontalSpacing = horizontalSpacing;
        this.verticalSpacing = verticalSpacing;
    }

    /**
     * Returns the horizontal spacing between the child items
     */
    public int getHorizontalSpacing() {
        return this.horizontalSpacing;
    }
}
}

Aucun commentaire:

Enregistrer un commentaire