-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Евгений Васильев @vasil.ev.genij #19
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package ru.yandex.yamblz.ui.views; | ||
|
||
import android.content.Context; | ||
import android.util.AttributeSet; | ||
import android.view.View; | ||
import android.view.ViewGroup; | ||
|
||
import static android.view.View.MeasureSpec.EXACTLY; | ||
import static android.view.View.MeasureSpec.UNSPECIFIED; | ||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; | ||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; | ||
|
||
public class LightweightHorizontalLayout extends ViewGroup { | ||
private static final String TAG = LightweightHorizontalLayout.class.getSimpleName(); | ||
private static final String ERROR_MSG = " supports at most one child with layout_width set to 'match_parent'!"; | ||
|
||
private static final int NONE = -1; | ||
|
||
private int[] childrenWidth; | ||
private int[] childrenHeight; | ||
private int childMaxHeight; | ||
|
||
public LightweightHorizontalLayout(Context context, AttributeSet attrs) { | ||
super(context, attrs); | ||
} | ||
|
||
|
||
@Override | ||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||
int widthMeasured = 0; | ||
int specialChildIndex = NONE; | ||
int limitlessSpec = MeasureSpec.makeMeasureSpec(0, UNSPECIFIED); | ||
|
||
childrenWidth = new int[getChildCount()]; | ||
childrenHeight = new int[childrenWidth.length]; | ||
|
||
for (int i = 0; i < childrenWidth.length; i++) { | ||
View child = getChildAt(i); | ||
|
||
if (child.getVisibility() == GONE) continue; | ||
|
||
child.measure(limitlessSpec, limitlessSpec); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. К слову, measureChild учитывает паддинги автоматически |
||
|
||
childrenWidth[i] = computeChildSize(child, true); | ||
if (childrenWidth[i] == MATCH_PARENT) { | ||
if (specialChildIndex != NONE) throw new IllegalArgumentException(TAG + ERROR_MSG); | ||
specialChildIndex = i; | ||
} else { | ||
widthMeasured += childrenWidth[i]; | ||
} | ||
|
||
childrenHeight[i] = computeChildSize(child, false); | ||
childMaxHeight = Math.max(childrenHeight[i], childMaxHeight); | ||
} | ||
|
||
int horizontalPadding = getPaddingLeft() + getPaddingRight(); | ||
int contentMaxWidth = MeasureSpec.getSize(widthMeasureSpec) - horizontalPadding; | ||
|
||
widthMeasured = Math.min(widthMeasured, contentMaxWidth); | ||
|
||
if (specialChildIndex != NONE) { | ||
childrenWidth[specialChildIndex] = contentMaxWidth - widthMeasured; | ||
widthMeasured = contentMaxWidth; | ||
} | ||
|
||
int verticalPadding = getPaddingTop() + getPaddingBottom(); | ||
int contentMaxHeight = MeasureSpec.getSize(heightMeasureSpec) - verticalPadding; | ||
|
||
int heightMeasured; | ||
if (MeasureSpec.getMode(heightMeasureSpec) == EXACTLY) { | ||
heightMeasured = childMaxHeight = contentMaxHeight; | ||
} else { | ||
heightMeasured = Math.min(childMaxHeight, contentMaxHeight); | ||
} | ||
|
||
setMeasuredDimension(widthMeasured + horizontalPadding, heightMeasured + verticalPadding); | ||
} | ||
|
||
|
||
private int computeChildSize(View child, boolean isWidth) { | ||
LayoutParams params = child.getLayoutParams(); | ||
int size = isWidth ? params.width : params.height; | ||
|
||
switch (size) { | ||
case MATCH_PARENT: | ||
return MATCH_PARENT; | ||
|
||
case WRAP_CONTENT: | ||
return isWidth ? child.getMeasuredWidth() : child.getMeasuredHeight(); | ||
|
||
default: | ||
return size; | ||
} | ||
} | ||
|
||
|
||
@Override | ||
protected void onLayout(boolean changed, int l, int t, int r, int b) { | ||
int drawn = getPaddingLeft(); | ||
int topPadding = getPaddingTop(); | ||
|
||
for (int i = 0; i < this.getChildCount(); i++) { | ||
int width = childrenWidth[i]; | ||
|
||
int height = childrenHeight[i]; | ||
if (height == MATCH_PARENT) { | ||
height = childMaxHeight; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. а почему getMeasuredHeight не стал использовать? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. В onMeasure() я определяю размеры детей с помощью MeasureSpec.makeMeasureSpec(0, UNSPECIFIED). Это позволяет определить их "пожелания" и оставить право выбора за собой, сохраняя фактические значения в массивах для последующей отрисовки. При таком раскладе getMeasuredHeight() в onLayout() у всех детей будет возвращать значение равное высоте родительского лейаута. Чтобы этого избежать и использовать getMeasuredHeight(), на этапе measure следовало еще раз вызвать child.measure(wSpec, hSpec) с модом EXACTLY, но по заданию второго такого вызова быть не должно. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Мне кажется UNSPECIFIED использовать не совсем верно, так как нас то особо не интересуют пожелания потомков, у нас же есть ограничения, которые идут от родителя, UNSPECIFIED может быть только тогда, когда LightweightHorizontalLayout лежит в HorizontalScrollView, например. |
||
} | ||
|
||
getChildAt(i).layout(drawn, topPadding, drawn + width, height + topPadding); | ||
|
||
drawn += width; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,163 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent"> | ||
<LinearLayout | ||
xmlns:android="http://schemas.android.com/apk/res/android" | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
android:orientation="vertical"> | ||
|
||
<TextView | ||
<FrameLayout | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
android:text="@string/content" | ||
android:textSize="42sp" | ||
android:gravity="center" | ||
/> | ||
android:layout_height="0dp" | ||
android:layout_weight="1" | ||
android:background="#eee"> | ||
|
||
</FrameLayout> | ||
<ru.yandex.yamblz.ui.views.LightweightHorizontalLayout | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
android:layout_margin="10dp" | ||
android:background="#f97" | ||
android:padding="10dp"> | ||
|
||
<View | ||
android:layout_width="20dp" | ||
android:layout_height="100dp" | ||
android:background="#0f0"/> | ||
|
||
<TextView | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:background="#f00" | ||
android:padding="10dp" | ||
android:text="@string/content"/> | ||
|
||
<TextView | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
android:background="#ff0" | ||
android:padding="10dp" | ||
android:text="@string/app_name" | ||
android:textSize="32sp"/> | ||
|
||
</ru.yandex.yamblz.ui.views.LightweightHorizontalLayout> | ||
|
||
</FrameLayout> | ||
|
||
<FrameLayout | ||
android:layout_width="match_parent" | ||
android:layout_height="0dp" | ||
android:layout_weight="1" | ||
android:background="#19f"> | ||
|
||
<ru.yandex.yamblz.ui.views.LightweightHorizontalLayout | ||
android:layout_width="wrap_content" | ||
android:layout_height="match_parent" | ||
android:background="#d7f"> | ||
|
||
<TextView | ||
android:layout_width="150dp" | ||
android:layout_height="match_parent" | ||
android:background="#f00" | ||
android:padding="10dp" | ||
android:text="@string/app_name" | ||
android:textSize="32sp"/> | ||
|
||
<TextView | ||
android:layout_width="55dp" | ||
android:layout_height="100dp" | ||
android:background="#0f0" | ||
android:paddingTop="10dp" | ||
android:text="@string/content" | ||
android:textSize="32sp"/> | ||
|
||
<View | ||
android:layout_width="55dp" | ||
android:layout_height="100dp" | ||
android:background="#f00"/> | ||
|
||
</ru.yandex.yamblz.ui.views.LightweightHorizontalLayout> | ||
|
||
</FrameLayout> | ||
|
||
<FrameLayout | ||
android:layout_width="match_parent" | ||
android:layout_height="0dp" | ||
android:layout_weight="1" | ||
android:background="#eee"> | ||
|
||
<ru.yandex.yamblz.ui.views.LightweightHorizontalLayout | ||
android:layout_width="wrap_content" | ||
android:layout_height="match_parent" | ||
android:background="#fff"> | ||
|
||
<TextView | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
android:background="#ff0" | ||
android:padding="10dp" | ||
android:text="@string/content" | ||
android:textSize="32sp"/> | ||
|
||
<View | ||
android:layout_width="20dp" | ||
android:layout_height="100dp" | ||
android:background="#0f0"/> | ||
|
||
<View | ||
android:layout_width="1dp" | ||
android:layout_height="match_parent" | ||
android:background="#000"/> | ||
|
||
<View | ||
android:layout_width="20dp" | ||
android:layout_height="100dp" | ||
android:background="#0f0"/> | ||
|
||
<View | ||
android:layout_width="1dp" | ||
android:layout_height="match_parent" | ||
android:background="#000"/> | ||
|
||
<View | ||
android:layout_width="20dp" | ||
android:layout_height="100dp" | ||
android:background="#0f0"/> | ||
|
||
<View | ||
android:layout_width="1dp" | ||
android:layout_height="match_parent" | ||
android:background="#000"/> | ||
|
||
<View | ||
android:layout_width="20dp" | ||
android:layout_height="100dp" | ||
android:background="#0f0"/> | ||
|
||
<View | ||
android:layout_width="1dp" | ||
android:layout_height="match_parent" | ||
android:background="#000"/> | ||
|
||
<View | ||
android:layout_width="20dp" | ||
android:layout_height="100dp" | ||
android:background="#0f0"/> | ||
|
||
<View | ||
android:layout_width="1dp" | ||
android:layout_height="match_parent" | ||
android:background="#000"/> | ||
|
||
<View | ||
android:layout_width="20dp" | ||
android:layout_height="100dp" | ||
android:background="#0f0"/> | ||
|
||
<View | ||
android:layout_width="1dp" | ||
android:layout_height="match_parent" | ||
android:background="#000"/> | ||
|
||
</ru.yandex.yamblz.ui.views.LightweightHorizontalLayout> | ||
|
||
</FrameLayout> | ||
|
||
</LinearLayout> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Круто, что паддинги обработал, но код работает правильно, только если width wrap_content, с match_parent или фиксированной шириной растягивающаяся вью не отображается
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Прошу пояснить, что именно и в каких случая не работает; в демо-лейауте и, соответственно, на скринах выше есть вьюхи со всеми перечисленными значениями width, и всё ок.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Я имел ввиду LightweightHorizontalLayout, если у нее выставить match_parent или фиксированную ширину, то вьюха с match_parent не отображается
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Да, была логическая ошибка.
Пофиксил.