Проблемы выравнивания с gridlayout, содержащим изображения
Android Studio 1.2
Привет,
Я пытаюсь сделать это выравнивание правильным для следующего каркаса.
Я использую только gridlayout для этого и не хочу использовать линейный или относительный макет или вложенные макеты.
Я получил его близко, используя следующий xml. Просто нужна помощь с некоторыми последними штрихами, чтобы сделать его идеальным.
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightLarge"
android:columnCount="6"
android:orientation="horizontal"
android:padding="6dp">
<TextView
android:id="@+id/tvDate"
android:layout_gravity="start"
android:text="16 Mar 2015"
android:textSize="18sp"/>
<TextView
android:id="@+id/tvCorrectTxt"
android:layout_gravity="end"
android:layout_columnSpan="2"
android:text="Correct 20"
android:textSize="18sp"/>
<ImageView
android:id="@+id/ivCorrect"
android:layout_columnSpan="2"
android:layout_gravity="top"
android:src="@drawable/ic_action_good"/>
<ImageView
android:id="@+id/ivArrow"
android:layout_rowSpan="2"
android:layout_gravity="center"
android:src="@drawable/ic_action_next_item"/>
<TextView
android:id="@+id/tvTime"
android:layout_gravity="start|bottom"
android:text="22:15"
android:textSize="18sp"/>
<TextView
android:id="@+id/tvIncorrect"
android:layout_gravity="end|bottom"
android:layout_columnSpan="2"
android:text="Incorrect 18"
android:textSize="18sp"/>
<ImageView
android:id="@+id/ivIncorrect"
android:layout_gravity="bottom"
android:src="@drawable/ic_action_bad"/>
</GridLayout>
Большое спасибо за любые предложения,
2 ответа:
Ваш макет (с рисунка) выглядит довольно статичным - не так много движущихся частей. Почему бы не реализовать его как обычай
Viewgroup
? Так как вы после спектакля,это было бы правильно.Позиционирование детских представлений будет происходить относительно
ViewGroup
, а не самих детей. Математика вовлечена:Столбцы (childLeft & childRight)
- разделите доступную ширину (actualWidth - paddingLeft-paddingRight) на 6 равных интервалов столбцы
- TextViews tvDate & tvTime смываются влево
- TextViews tvCorrectTxt & tvIncorrect сбрасываются прямо в 4-й колонке
- ivCorrect и ivIncorrect расположены горизонтально внутри 5-го столбца
- иварроу смывается прямо в 6-й колонке
Строки (childTop & childBottom)
У нас есть две строки для отображения. Чтобы иметь равное расстояние над, между и под рядами, мы выровняем вертикаль первого ряда центр с
container's height/3
==>y = 0.333*availableHeight
; вертикальный Центр второго ряда будет сидеть на2*container's height/3
==>y = 0.666*availableHeight
- ivArrow будет центрирован по вертикали в пределах доступных высоты.
CusViewGroup:
public class CusViewGroup extends ViewGroup { // In case we have to explicitly set the viewgroup's height private int mDesiredHeight; public CusViewGroup(Context context, AttributeSet attrs) { super(context, attrs); // Attribute array int[] attrss = new int[] { android.R.attr.listPreferredItemHeightLarge }; TypedArray a = context.getTheme().obtainStyledAttributes(attrss); // 200 is being used as the default value. // This should actually be defined in res/values/dimens.xml // and retrieved using // getResources.getDimensionPixelSize(R.dimen.defaultListItemHeight) mDesiredHeight = a.getDimensionPixelSize(0, 200); a.recycle(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { final int count = getChildCount(); final int parentLeft = getPaddingStart(); final int parentRight = right - left - getPaddingEnd(); final int parentTop = getPaddingTop(); final int parentBottom = bottom - top - getPaddingBottom(); final int availableParentWidth = parentRight - parentLeft; final int availableParentHeight = parentBottom - parentTop; final int columnWidth = availableParentWidth/6; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int width = child.getMeasuredWidth(); final int height = child.getMeasuredHeight(); int childLeft, childTop; // We can use the assigned ids and calculate // view positions. switch(child.getId()) { case R.id.tvDate: childLeft = parentLeft; childTop = parentTop + availableParentHeight/3 - height/2; break; case R.id.tvCorrectTxt: childLeft = parentLeft + columnWidth*4 - width; childTop = parentTop + availableParentHeight/3 - height/2; break; case R.id.ivCorrect: childLeft = parentLeft + columnWidth*4 + (columnWidth - width) / 2; childTop = parentTop + availableParentHeight/3 - height/2; break; case R.id.ivArrow: childLeft = parentRight - width; childTop = parentTop + (availableParentHeight - height) / 2; break; case R.id.tvTime: childLeft = parentLeft; childTop = parentTop + 2*availableParentHeight/3 - height/2; break; case R.id.tvIncorrect: childLeft = parentLeft + columnWidth*4 - width; childTop = parentTop + 2*availableParentHeight/3 - height/2; break; case R.id.ivIncorrect: childLeft = parentLeft + columnWidth*4 + (columnWidth - width) / 2; childTop = parentTop + 2*availableParentHeight/3 - height/2; break; default: // We shouldn't be here child.setVisibility(View.GONE); continue; } // layout child child.layout(childLeft, childTop, childLeft + width, childTop + height); } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // We're using an exact value for height & MATCH_PARENT for width int height = getMeasuredHeight(); if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY) { // Use mDesiredHeight if heightMeasureSpec is not // measured exactly. height = mDesiredHeight; // Update heightMeasureSpec heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); } setMeasuredDimension(getMeasuredWidth(), height); final int count = getChildCount(); // measure children for (int i = 0; i < count; i++) { final View child = getChildAt(i); int childWidthMeasureSpec; int childHeightMeasureSpec; childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, LayoutParams.WRAP_CONTENT); childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 0, LayoutParams.WRAP_CONTENT); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } } }
Теперь, для xml, нам не нужно много определять. Просто добавьте всех детей и позвольте
onLayout(..)
обрабатывать места размещения.<?xml version="1.0" encoding="utf-8"?> <!-- paddingStart=18dp(10dp + 8dp) because ivArrow's size(32dp) - optical square(24dp) = 8dp --> <your.package.name.CusViewGroup xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeightLarge" android:paddingStart="18dp" android:paddingEnd="10dp" android:background="#ffffff"> <TextView android:id="@+id/tvDate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="16 Mar 2015" android:textColor="#858585" android:textSize="18sp"/> <TextView android:id="@+id/tvCorrectTxt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Correct 20" android:textColor="#858585" android:textSize="18sp"/> <ImageView android:id="@+id/ivCorrect" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_action_good"/> <ImageView android:id="@+id/ivArrow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_action_next_item"/> <TextView android:id="@+id/tvTime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="22:15" android:textSize="18sp" android:textColor="#858585"/> <TextView android:id="@+id/tvIncorrect" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Incorrect 18" android:textColor="#858585" android:textSize="18sp"/> <ImageView android:id="@+id/ivIncorrect" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_action_bad"/> </com.appeaser.playground.CusViewGroup>
Если вы хотите, чтобы дочерние представления поддерживали отступы / поля, вы можете сделать это, изменив
onLayout(...)
&onMeasure(...)
. Чтобы поддержать RTL, изменитеonLayout(...)
.Портрет :
Пейзаж :
Я предлагаю вам поиграть с атрибутомcolumnWeight , чтобы настроить размер ячеек. Я также предлагаю назначить определенное измерение вашим изображениям.
Взгляните на мою отредактированную версию, она дает почти желаемый результат! (Да, я использую различные ресурсы изображений;)):
Вот XML:
<?xml version="1.0" encoding="utf-8"?> <GridLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeightLarge" android:columnCount="6" android:orientation="horizontal" android:padding="8dp"> <TextView android:id="@+id/tvDate" android:layout_gravity="start" android:text="16 Mar 2015" android:layout_columnWeight="1" android:textSize="18sp"/> <TextView android:id="@+id/tvCorrectTxt" android:layout_gravity="end" android:layout_columnSpan="2" android:text="Correct 20" android:textSize="18sp"/> <ImageView android:id="@+id/ivCorrect" android:layout_columnSpan="2" android:layout_gravity="center_horizontal|top" android:layout_width="25dp" android:layout_height="25dp" android:src="@drawable/ic_action_good"/> <ImageView android:id="@+id/ivArrow" android:layout_rowSpan="2" android:layout_columnWeight="0" android:layout_gravity="center" android:src="@drawable/ic_action_next_item"/> <TextView android:id="@+id/tvTime" android:layout_columnWeight="1" android:layout_gravity="start|bottom" android:text="22:15" android:textSize="18sp"/> <TextView android:id="@+id/tvIncorrect" android:layout_gravity="end|bottom" android:layout_columnSpan="2" android:layout_columnWeight="0" android:text="Incorrect 18" android:textSize="18sp"/> <ImageView android:id="@+id/ivIncorrect" android:layout_columnWeight="2" android:layout_width="25dp" android:layout_height="25dp" android:layout_gravity="center_horizontal|bottom" android:src="@drawable/ic_action_bad"/> </GridLayout>