2017-02-05 08:34:55 +01:00
|
|
|
/* Copyright 2017 Andrew Dawson
|
|
|
|
*
|
2017-04-10 02:12:31 +02:00
|
|
|
* This file is a part of Tusky.
|
2017-02-05 08:34:55 +01:00
|
|
|
*
|
2017-04-10 02:12:31 +02:00
|
|
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
|
|
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
2017-02-05 08:34:55 +01:00
|
|
|
*
|
|
|
|
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
2017-04-10 02:12:31 +02:00
|
|
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
|
|
* Public License for more details.
|
2017-02-05 08:34:55 +01:00
|
|
|
*
|
2017-04-10 02:12:31 +02:00
|
|
|
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
|
|
|
* see <http://www.gnu.org/licenses>. */
|
2017-02-05 08:34:55 +01:00
|
|
|
|
2017-05-15 12:07:01 +02:00
|
|
|
package com.keylesspalace.tusky.view;
|
2017-02-01 23:01:34 +01:00
|
|
|
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.res.TypedArray;
|
|
|
|
import android.util.AttributeSet;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
|
2017-05-05 00:55:34 +02:00
|
|
|
import com.keylesspalace.tusky.R;
|
2017-05-15 12:07:01 +02:00
|
|
|
import com.keylesspalace.tusky.util.Assert;
|
2017-05-05 00:55:34 +02:00
|
|
|
|
2017-02-01 23:01:34 +01:00
|
|
|
public class FlowLayout extends ViewGroup {
|
|
|
|
private int paddingHorizontal; // internal padding between child views
|
|
|
|
private int paddingVertical; //
|
|
|
|
|
|
|
|
public FlowLayout(Context context, AttributeSet attrs) {
|
|
|
|
this(context, attrs, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
|
|
|
|
super(context, attrs, defStyle);
|
2017-06-02 09:12:02 +02:00
|
|
|
TypedArray a = context.getTheme()
|
|
|
|
.obtainStyledAttributes(attrs, R.styleable.FlowLayout, 0, 0);
|
2017-02-01 23:01:34 +01:00
|
|
|
try {
|
2017-06-02 09:12:02 +02:00
|
|
|
paddingHorizontal = a.getDimensionPixelSize(R.styleable.FlowLayout_paddingHorizontal, 0);
|
2017-02-01 23:01:34 +01:00
|
|
|
paddingVertical = a.getDimensionPixelSize(R.styleable.FlowLayout_paddingVertical, 0);
|
|
|
|
} finally {
|
|
|
|
a.recycle();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
2017-02-22 20:13:51 +01:00
|
|
|
Assert.expect(MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED);
|
2017-02-01 23:01:34 +01:00
|
|
|
int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
|
|
|
|
int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
|
|
|
|
int count = getChildCount();
|
|
|
|
int x = getPaddingLeft();
|
|
|
|
int y = getPaddingTop();
|
|
|
|
int childHeightMeasureSpec;
|
|
|
|
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
|
|
|
|
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
|
|
|
|
} else {
|
|
|
|
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
|
|
|
}
|
2017-06-02 09:12:02 +02:00
|
|
|
int rowHeight = 0;
|
2017-02-01 23:01:34 +01:00
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
View child = getChildAt(i);
|
|
|
|
if (child.getVisibility() != GONE) {
|
2017-06-02 09:12:02 +02:00
|
|
|
int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST);
|
|
|
|
child.measure(widthSpec, childHeightMeasureSpec);
|
2017-07-12 23:03:32 +02:00
|
|
|
child.getLayoutParams();
|
|
|
|
int childWidth = child.getMeasuredWidth();
|
2017-06-02 09:12:02 +02:00
|
|
|
int childHeight = child.getMeasuredHeight();
|
2017-07-12 23:03:32 +02:00
|
|
|
if (x + childWidth > width) {
|
2017-02-01 23:01:34 +01:00
|
|
|
x = getPaddingLeft();
|
2017-06-02 09:12:02 +02:00
|
|
|
y += rowHeight;
|
|
|
|
rowHeight = childHeight + paddingVertical;
|
|
|
|
} else {
|
|
|
|
rowHeight = Math.max(rowHeight, childHeight + paddingVertical);
|
2017-02-01 23:01:34 +01:00
|
|
|
}
|
2017-07-12 23:03:32 +02:00
|
|
|
x += childWidth + paddingHorizontal;
|
2017-02-01 23:01:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
|
2017-06-02 09:12:02 +02:00
|
|
|
height = y + rowHeight;
|
2017-02-01 23:01:34 +01:00
|
|
|
} else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
|
2017-06-02 09:12:02 +02:00
|
|
|
if (y + rowHeight < height) {
|
|
|
|
height = y + rowHeight;
|
2017-02-01 23:01:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
height += 5; // Fudge to avoid clipping bottom of last row.
|
|
|
|
setMeasuredDimension(width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
|
|
|
final int width = r - l;
|
|
|
|
int x = getPaddingLeft();
|
|
|
|
int y = getPaddingTop();
|
2017-06-02 09:12:02 +02:00
|
|
|
int rowHeight = 0;
|
2017-02-01 23:01:34 +01:00
|
|
|
for (int i = 0; i < getChildCount(); i++) {
|
|
|
|
View child = getChildAt(i);
|
|
|
|
if (child.getVisibility() != GONE) {
|
|
|
|
int childWidth = child.getMeasuredWidth();
|
|
|
|
int childHeight = child.getMeasuredHeight();
|
|
|
|
if (x + childWidth > width) {
|
|
|
|
x = getPaddingLeft();
|
2017-06-02 09:12:02 +02:00
|
|
|
y += rowHeight;
|
|
|
|
rowHeight = childHeight + paddingVertical;
|
|
|
|
} else {
|
|
|
|
rowHeight = Math.max(childHeight, rowHeight);
|
2017-02-01 23:01:34 +01:00
|
|
|
}
|
|
|
|
child.layout(x, y, x + childWidth, y + childHeight);
|
|
|
|
x += childWidth + paddingHorizontal;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-02 09:12:02 +02:00
|
|
|
}
|