Проблемы выравнивания с 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 3

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>