Заполните экран сеткой дочерних представлений, но дочерние представления имеют половину ожидаемого размера - PullRequest
0 голосов
/ 10 мая 2019

Я пишу игру, в которой счетчики можно перетаскивать по экрану. Я хочу использовать ImageView дочернее представление для каждого счетчика и установить абсолютные позиции внутри FrameLayout родительского представления.

Я прочитал несколько SO-сообщений о преимуществах различных классов компоновки по сравнению с устаревшим AbsoluteLayout, и я не хочу использовать RelativeLayout, потому что счетчики должны перемещаться независимо друг от друга. Похоже, что ни один из этих постов не посвящен конкретной проблеме, с которой я сталкиваюсь, хотя я был бы рад, если бы кто-то мог указать мне на такой вопрос.

Вот макет XML:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_game"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff808080">
</FrameLayout>

Поскольку я не хочу делать предположения о размере экрана, я устанавливаю размер каждого дочернего элемента в виде доли от размера родителя внутри onMeasure():

package uk.co.fractalmaze.counterspin.widget

import android.content.Context
import android.graphics.Color
import android.util.Log
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView

class CounterView(context: Context, private val label: String, private val offset: Int) : ImageView(context)
{
    init
    {
        // Set the background color.
        val color = if (offset > 0) Color.GREEN else Color.RED
        setBackgroundColor(color)
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int)
    {
        // Set the position and size.
        val parentWidth = MeasureSpec.getSize(widthMeasureSpec)
        val parentHeight = MeasureSpec.getSize(heightMeasureSpec)
        val size = Math.min(parentWidth, parentHeight) / 2
        val left = offset * size
        Log.i(javaClass.simpleName, "Parent size ($parentWidth, $parentHeight) to $label child position ($left, 0) size $size")
        setMeasuredDimension(size, size)
        layoutParams = createLayoutParams(left, 0, size, size)
    }

    private fun createLayoutParams(left: Int, top: Int, width: Int, height: Int): ViewGroup.LayoutParams
    {
        // Create a margin params object.
        val params = FrameLayout.LayoutParams(width, height)
        params.leftMargin = left
        params.topMargin = top
        return params
    }
}

Для полноты, вот где я добавляю дочерние представления к родителю:

package uk.co.fractalmaze.counterspin.activity

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.widget.FrameLayout
import uk.co.fractalmaze.counterspin.R
import uk.co.fractalmaze.counterspin.widget.CounterView

class GameActivity : AppCompatActivity()
{
    override fun onCreate(savedInstanceState: Bundle?)
    {
        // Call the superclass.
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_game)

        // Add a left and right view to the group.
        val group = findViewById<FrameLayout>(R.id.activity_game)
        group.addView(CounterView(applicationContext, "left", 0))
        group.addView(CounterView(applicationContext, "right", 1))
    }
}

Вот скриншот с результатами:

enter image description here

Я ожидаю, что красный и зеленый дочерние виды появятся рядом и заполнят экран, но вместе они занимают только половину ширины. Это подтверждается выводом logcat, который показывает расшифрованную родительскую ширину MeasureSpec как 1080, а затем 540, что дает дочернюю ширину 540, а затем 270. Это выполняется на смоделированном пикселе 3 с шириной экрана 1080 пикселей:

2019-05-09 22:06:33.493 15575-15575/uk.co.fractalmaze.counterspin I/CounterView: Parent size (1080, 1808) to left child position (0, 0) size 540
2019-05-09 22:06:33.493 15575-15575/uk.co.fractalmaze.counterspin I/CounterView: Parent size (1080, 1808) to right child position (540, 0) size 540
2019-05-09 22:06:33.560 15575-15575/uk.co.fractalmaze.counterspin I/CounterView: Parent size (540, 540) to left child position (0, 0) size 270
2019-05-09 22:06:33.561 15575-15575/uk.co.fractalmaze.counterspin I/CounterView: Parent size (540, 540) to right child position (270, 0) size 270

Может кто-нибудь сказать мне:

  1. Почему родительский вид изменяет размеры до ширины 540?
  2. Как заставить дочерние представления заполнять все 1080 пикселей?

Ответы [ 2 ]

0 голосов
/ 10 мая 2019

У меня есть обходной путь, но я не уверен, почему это работает.Я изменил CounterView.onMeasure(), поэтому он создает параметры макета с нужным размером представления parent :

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int)
    {
        // Set the position and size.
        val parentWidth = MeasureSpec.getSize(widthMeasureSpec)
        val parentHeight = MeasureSpec.getSize(heightMeasureSpec)
        val parentSize = Math.min(parentWidth, parentHeight)
        val size = parentSize / 2
        val left = offset * size
        Log.i(javaClass.simpleName, "Parent size ($parentWidth, $parentHeight) to $label child position ($left, 0)")
        setMeasuredDimension(size, size)
        layoutParams = createLayoutParams(left, 0, parentSize, parentSize)
    }

Это был результат:

Android Simulator

Обратите внимание, что вывод logcat показывает размер родительского представления , а не , деленный пополам:

2019-05-10 17:51:16.335 18623-18623/? I/CounterView: Parent size (1080, 1808) to left child position (0, 0)
2019-05-10 17:51:16.336 18623-18623/? I/CounterView: Parent size (1080, 1808) to right child position (540, 0)
2019-05-10 17:51:16.386 18623-18623/? I/CounterView: Parent size (1080, 1080) to left child position (0, 0)
2019-05-10 17:51:16.389 18623-18623/? I/CounterView: Parent size (1080, 1080) to right child position (540, 0)

Этого достаточно, чтобы позволить мне продолжить написание приложения, но кто-нибудь может объяснить, что здесь происходит, пожалуйста?

0 голосов
/ 10 мая 2019

Используйте LinearLayout вместо FrameLayout, например:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:weightSum="2">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#ff0000">
        <!--child 1-->
    </LinearLayout>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#00ff00">
        <!--child 2-->
    </LinearLayout>

</LinearLayout>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...