如何制作GridLayout来相应地更改其子视图的大小?

时间:2019-08-22 12:03:25

标签: android androidx android-gridlayout

背景

我需要像“电话”应用上那样制作类似于拨号盘的视图。

我正在使用View的GridLayout。每个单元格的大小相同,并且仅包含一个简单的TextView,应在需要时更改其字体大小。

问题

我已经成功了,但是由于某些原因,根据给定的空间,它不能很好地工作。

如果有很多空间,则可以正常工作:

enter image description here

但是,当它变小时(例如,小屏幕,风景,分割窗口...),只有网格的顶部按钮才可见,并且它们甚至都没有改变其字体大小,就好像它们都是希望拥有最大的尺寸:

enter image description here

我尝试过的

我试图修改视图的各种属性,但没有帮助。

不过,我知道Phone应用程序的拨号盘并没有真正改变其字体大小。达到一定大小后,它会正常显示,如果太小,它将更改为其他布局。这对于横向和拆分窗口模式尤其重要。

这是我编写的代码(我更改了“ layout_constraintHeight_percent”的值以检查顶部区域的各种尺寸):

渐变

...
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.core:core-ktx:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.gridlayout:gridlayout:1.0.0'
...

QueryKeyboard.kt

class QueryKeyboard @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : GridLayout(context, attrs, defStyle) {
    init {
        orientation = HORIZONTAL
        clipChildren = false
        clipToPadding = false
        columnCount = 3
        rowCount = 4
        //workaround for a weird issue of seeing just 3 huge buttons, instead of all
        val runnable = Runnable {
            for (i in 1..9)
                addView(generateGridTextButton(i.toString()))
            addView(generateGridTextButton("*"))
            addView(generateGridTextButton("0"))
            addView(generateGridTextButton("+"))
        }
        if (isInEditMode)
            runnable.run()
        else
            this.doOnPreDraw { runnable.run() }
    }

    private fun generateGridTextButton(textToShowAndAddUponClick: CharSequence): TextView {
        val tv = LayoutInflater.from(context).inflate(R.layout.grid_text_button, this, false) as TextView
        tv.text = textToShowAndAddUponClick
        return tv
    }
}

grid_text_button.xml

<androidx.appcompat.widget.AppCompatTextView 
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:background="?attr/selectableItemBackgroundBorderless"
   android:breakStrategy="balanced"
   android:clickable="true"
   android:focusable="true"
   android:focusableInTouchMode="false"
   android:gravity="center"
   android:textColor="#000"
   android:textSize="36dp"
   app:autoSizeMaxTextSize="36dp"
   app:autoSizeMinTextSize="12dp"
   app:layout_columnWeight="1"
   app:layout_gravity="fill"
   app:layout_rowWeight="1"
   tools:layout_gravity="center"
   tools:targetApi="m"
   tools:text="1" />

activity_main.xml 中的用法:

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="0px"
        android:background="#33ff0000" android:gravity="center" android:text="some content"
        app:layout_constraintBottom_toTopOf="@id/queryKeyboard" app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHeight_percent="0.6" app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.sample.myapplication.QueryKeyboard
        android:id="@+id/queryKeyboard" android:layout_width="match_parent" android:layout_height="0px"
        app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/textView" />

</androidx.constraintlayout.widget.ConstraintLayout>

编辑:我试图用FrameLayout包装TextView,以显示每个单元格的大小:

grid_text_button.xml

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content"
    app:layout_columnWeight="1" app:layout_gravity="fill" app:layout_rowWeight="1">

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:background="?attr/selectableItemBackgroundBorderless" android:breakStrategy="balanced"
        android:clickable="true" android:focusable="true" android:focusableInTouchMode="false" android:gravity="center"
        android:textColor="#000" android:textSize="36sp" app:autoSizeMaxTextSize="36sp" app:autoSizeMinTextSize="12sp"
        tools:layout_gravity="center" tools:targetApi="m" tools:text="1" />
</FrameLayout>

QueryKeyboard.kt

class QueryKeyboard @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : GridLayout(context, attrs, defStyle) {
    private var cellBackgroundColor = 0xffff0000.toInt()

    init {
        orientation = HORIZONTAL
        clipChildren = false
        clipToPadding = false
        columnCount = 3
        rowCount = 4
        //workaround for a weird issue of seeing just 3 huge buttons, instead of all
        val runnable = Runnable {
            for (i in 1..9) {
                addView(generateGridTextButton(i.toString()))
            }
            addView(generateGridTextButton("*"))
            addView(generateGridTextButton("0"))
            addView(generateGridTextButton("+"))
        }
        if (isInEditMode)
            runnable.run()
        else
            this.doOnPreDraw { runnable.run() }
    }

    private fun switchColor() {
        cellBackgroundColor = if (cellBackgroundColor == 0xffff0000.toInt()) 0xff00ff00.toInt() else 0xffff0000.toInt()
    }

    private fun generateGridTextButton(textToShowAndAddUponClick: CharSequence): View {
        val view = LayoutInflater.from(context).inflate(R.layout.grid_text_button, this, false)
        switchColor()
        view.setBackgroundColor(cellBackgroundColor)
        view.textView.text = textToShowAndAddUponClick
        return view
    }
}

这是两种情况,什么时候可以正常工作,什么时候不可以:

enter image description here

enter image description here

与以前相同。获取3个单元格,文本不居中,并且不会自动调整其字体大小。

问题

  1. 为什么单元格不调整其大小,包括每个单元格的字体大小?当它太小时,我怎么会只看到3个单元格?我该如何解决?

  2. 还有更好的选择吗?我想我可以使用多个LinearLayout实例的LinearLayout,但这在这种情况下很奇怪...毕竟,您多久使用一次GridLayout ...:)

  3. 如何检测它何时太小,以至于我切换到另一个布局(例如在Phone应用程序上),包括它们使用的所有各种情况(甚至是分割窗口)?他们是否可能仅将限定符用于布局?如果是这样,在这种情况下推荐使用哪种方法?

2 个答案:

答案 0 :(得分:0)

  
    

为什么单元格不调整其大小,包括每个单元格的字体大小?我该如何解决?

  

一个单元可以基于两个主要约束条件动态调整其大小:the weight of its parentthe value of its textsize or childview。单元格上的文本大小固定会导致设计不一致。要解决此问题,您可以在父视图上设置宽度和高度与父级匹配的单元格的布局权重,也可以为目标设备创建不同尺寸的textsize。

  
    

还有更好的选择吗?我猜我可以使用多个LinearLayout实例的LinearLayout,但是在这种情况下这很奇怪...毕竟,您多久使用一次GridLayout ...:)

  

有一个更好的方法,那就是您当前正在实现的The GridLayout。使用缩进的LinearLayouts会限制您很多好处,并使您编写更多代码,例如需要切换或设置单元格动画,访问第n行的第n列,动态更改单元格跨度等情况。通过Gridlayout用几行代码完成。它比您想像的还要强大。

  
    

如何检测它何时太小,以至于我切换到另一个布局(例如在Phone应用程序上),包括它们使用的所有各种情况(甚至是分割窗口)?他们是否可能仅将限定符用于布局?如果是这样,建议在这种情况下使用哪种方法?

  

您无需检测任何东西,只需遵循指南,Android就会进行检测。

有两种方法可以根据Android Design guidelines

管理方案

第一: 为您的活动(layout/activity.xmllayout-land/activity.xml)创建布局横向和纵向模式

layout / activity.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools" 
 android:layout_width="match_parent"
android:layout_height="match_parent" 
android:orientation="vertical"
 android:weightSum="2"
tools:context=".MainActivity">

<TextView
    android:id="@+id/textView" 
    android:layout_width="match_parent" 
    android:layout_height="0dp"
    android:background="#33ff0000"
    android:gravity="center" android:text="some content"
    android:layout_weight="1" />

 <com.sample.myapplication.QueryKeyboard
    android:id="@+id/queryKeyboard" 
   android:layout_width="match_parent" 
    android:layout_height="0dp"
    android:layout_weight="1" />
 </LinearLayout>

layout-land / activity.xml

  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android
 xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent"
android:layout_height="match_parent" 
android:orientation="horizontal"
 android:weightSum="2"
tools:context=".MainActivity">
<TextView
    android:id="@+id/textView" 
    android:layout_width="0dp" 
    android:layout_height="match_parent"
    android:background="#33ff0000"
    android:gravity="center" android:text="some content"
    android:layout_weight="1" />

 <com.sample.myapplication.QueryKeyboard
    android:id="@+id/queryKeyboard" 
   android:layout_width="0dp" 
    android:layout_height="match_parent"
    android:layout_weight="1" />
 </LinearLayout>

此外,您需要处理各种屏幕尺寸的文本大小。

通过将Intuit android library添加到gradle的依赖项列表中,可以自动处理此textsize计算

dependencies {
   implementation 'com.intuit.ssp:ssp-android:1.0.6'
 }

然后在网格按钮中调用文本大小

 android:textSize="@dimens/_30ssp"

答案 1 :(得分:0)

好,我对布局文件做了一些更改,以避免出现3单元问题。它仍然会发生,但是尺寸要小得多。可悲的是,字体大小问题仍然存在,甚至这次很小。

如果有人找到原因,请告诉我。目前,我认为这是一个错误,因此我报告了here

grid_text_button.xml

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content"
    android:layout_height="wrap_content" android:background="?attr/selectableItemBackgroundBorderless"
    android:clickable="true" android:focusable="true" android:focusableInTouchMode="false" app:layout_columnWeight="1"
    app:layout_gravity="fill" app:layout_rowWeight="1" tools:layout_gravity="center">

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:layout_gravity="center" android:breakStrategy="balanced" android:gravity="center"
        android:textColor="#000" app:autoSizeMaxTextSize="36sp" app:autoSizeMinTextSize="12sp" tools:targetApi="m"
        tools:text="1" />
</FrameLayout>

QueryKeyboard.kt

class QueryKeyboard @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : GridLayout(context, attrs, defStyle) {
    //    private var cellBackgroundColor = 0xffff0000.toInt()
    init {
        orientation = HORIZONTAL
        clipChildren = false
        clipToPadding = false
        columnCount = 3
        rowCount = 4
        for (i in 1..9)
            addView(generateGridTextButton(i.toString()))
        addView(generateGridTextButton("*"))
        addView(generateGridTextButton("0"))
        addView(generateGridTextButton("+"))
    }

    //    private fun switchColor() {
    //        cellBackgroundColor = if (cellBackgroundColor == 0xffff0000.toInt()) 0xff00ff00.toInt() else 0xffff0000.toInt()
    //    }
    private fun generateGridTextButton(textToShowAndAddUponClick: CharSequence): View {
        val view = LayoutInflater.from(context).inflate(R.layout.grid_text_button, this, false)
        //        switchColor()
        //        view.setBackgroundColor(cellBackgroundColor)
        view.textView.text = textToShowAndAddUponClick
        return view
    }
}

GridLayout实现的替代方法没有这个问题,但是我仍然很奇怪地使用它,就像我写的那样,是LinearLayouts的LinearLayout:

class QueryKeyboard2 @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : LinearLayout(context, attrs, defStyleAttr) {
    //private var cellBackgroundColor = 0xffff0000.toInt()

    init {
        orientation = VERTICAL
        clipChildren = false
        clipToPadding = false
        val columnCount = 3
        val rowCount = 4
        val cellsList = ArrayList<View>()
        for (i in 1..9)
            cellsList.add(generateGridTextButton(i.toString()))
        cellsList.add(generateGridTextButton("*"))
        cellsList.add(generateGridTextButton("0"))
        cellsList.add(generateGridTextButton("+"))
        for (i in 0 until rowCount) {
            val rowLayout = generateRowLayout(context)
            for (j in 0 until columnCount) {
                val cellView = cellsList[i * columnCount + j]
                val cellLayoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT)
                cellLayoutParams.weight = 1f
                rowLayout.addView(cellView, cellLayoutParams)
            }
            //            switchColor()
            //            rowLayout.setBackgroundColor(cellBackgroundColor)
            addView(rowLayout)
        }
    }

    private fun generateRowLayout(context: Context): LinearLayout {
        val result = LinearLayout(context)
        result.layoutParams = LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0)
        (result.layoutParams as LayoutParams).weight = 1f
        result.orientation = HORIZONTAL
        return result
    }

    //private fun switchColor() {
    //    cellBackgroundColor = if (cellBackgroundColor == 0xffff0000.toInt()) 0xff00ff00.toInt() else 0xffff0000.toInt()
    //}

    private fun generateGridTextButton(textToShowAndAddUponClick: CharSequence): View {
        val view = LayoutInflater.from(context).inflate(R.layout.grid_text_button, this, false)
        //switchColor()
        //view.setBackgroundColor(cellBackgroundColor)
        view.textView.text = textToShowAndAddUponClick
        return view
    }
}

至于试图使其仅在有足够的空间(高度)时显示,我将布局设置为在“ res / layout-h400dp”上使用(可以根据需要进行更改),一种,通常是“ res / layout”的拨号盘在右侧。