電卓アプリを持っていて、次のようなレイアウトを作成したい場合、すべての画面サイズに合わせてボタンと表示を拡大縮小するにはどうすればよいでしょうか?
私が調べたアイデア:
各コンポーネントの高さと幅をプログラムで計算します。プログラムでビューを作成すると、最大限の能力が得られますが、理想的ではありません。UI を XML で記述したいと考えています。
レイアウト ウェイトを使用して LinearLayout をネストします。これは機能しますが、ウェイトをネストしているため、lint によってパフォーマンスの警告が表示されます。その上、テキストサイズは考慮されていません。そのため、小さな画面ではテキストが途切れます。逆に、大画面では文字が小さすぎます。
編集: 3. ネストされた重みを持つ TableLayout を使用します。これらが LinearLayout から拡張されていることを考えると、lint 警告の欠如は無関係であると思いますが、これは依然としてパフォーマンスの低下を引き起こしますか?
より良い方法はありますか?明らかな何かが欠けているように感じます
編集 2: 誰かがこのソリューションに興味がある場合は、(raphw が提案したように) カスタム レイアウトを作成し、ソース コードをここに投稿します。
EvenSpaceGridLayout.java:
package com.example.evenspacegridlayout;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class EvenSpaceGridLayout extends ViewGroup {
private int mNumColumns;
public EvenSpaceGridLayout(Context context) {
super(context);
}
public EvenSpaceGridLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.EvenSpaceGridLayout);
try {
mNumColumns = a.getInteger(
R.styleable.EvenSpaceGridLayout_num_columns, 1);
} finally {
a.recycle();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
// Calculate how many cells we need
int cellCount = countCellsNeeded();
// Calculate number of rows needed given the number of cells
int numRows = cellCount / mNumColumns;
// Calculate width/height of each individual cell
int cellWidth = widthSize / mNumColumns;
int cellHeight = heightSize / numRows;
// Measure children
measureChildrenViews(cellWidth, cellHeight);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());
}
}
private int countCellsNeeded() {
int cellCount = 0;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int spanColumns = lp.spanColumns;
// If it's trying to span too far, make it span the maximum possible
if (spanColumns > mNumColumns) {
spanColumns = mNumColumns;
}
int remainingCellsInRow = mNumColumns - (cellCount % mNumColumns);
if (remainingCellsInRow - spanColumns < 0) {
cellCount += remainingCellsInRow + spanColumns;
} else {
cellCount += spanColumns;
}
}
// Round off the last row
if ((cellCount % mNumColumns) != 0) {
cellCount += mNumColumns - (cellCount % mNumColumns);
}
return cellCount;
}
private void measureChildrenViews(int cellWidth, int cellHeight) {
int cellCount = 0;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int spanColumns = lp.spanColumns;
// If it's trying to span too far, make it span the maximum possible
if (spanColumns > mNumColumns) {
spanColumns = mNumColumns;
}
// If it can't fit on the current row, skip those cells
int remainingCellsInRow = mNumColumns - (cellCount % mNumColumns);
if (remainingCellsInRow - spanColumns < 0) {
cellCount += remainingCellsInRow;
}
// Calculate x and y coordinates of the view
int x = (cellCount % mNumColumns) * cellWidth;
int y = (cellCount / mNumColumns) * cellHeight;
lp.x = x;
lp.y = y;
child.measure(MeasureSpec.makeMeasureSpec(cellWidth * spanColumns, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(cellHeight, MeasureSpec.EXACTLY));
cellCount += spanColumns;
}
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
@Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p.width, p.height);
}
public static class LayoutParams extends ViewGroup.LayoutParams {
int x, y;
public int spanColumns;
public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.EvenSpaceGridLayout_LayoutParams);
try {
spanColumns = a
.getInteger(
R.styleable.EvenSpaceGridLayout_LayoutParams_span_columns,
1);
// Can't span less than one column
if (spanColumns < 1) {
spanColumns = 1;
}
} finally {
a.recycle();
}
}
public LayoutParams(int w, int h) {
super(w, h);
}
}
}
attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="EvenSpaceGridLayout">
<attr name="num_columns" format="integer" />
</declare-styleable>
<declare-styleable name="EvenSpaceGridLayout_LayoutParams">
<attr name="span_columns" format="integer" />
</declare-styleable>
</resources>
使用方法は次のとおりです。
<com.example.evenspacegridlayout.EvenSpaceGridLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:grid="http://schemas.android.com/apk/res/com.example.evenspacegridlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
grid:num_columns="4" >
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="CL" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Del" />
<!-- empty cell -->
<View
android:layout_width="0dp"
android:layout_height="0dp" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="/" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="7" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="8" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="9" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="*" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="4" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="5" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="6" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="-" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="1" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="2" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="3" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="+" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="." />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="0" />
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="="
grid:span_columns="2" />
</com.example.evenspacegridlayout.EvenSpaceGridLayout>
そして最終結果: