私GridViewは本質的にであるビューの束を表示するためにを使用していますLinearLayouts。LinearLayoutsすべてを正方形にしたいが、動的なサイズにすることも必要です。つまり、2つの列がありLinearLayouts、画面のサイズに応じてストレッチしますが、正方形のままにします。xmlレイアウトを介してこれを行う方法はありますか、それともプログラムで高さと幅を設定する必要がありますか?
回答:
正方形のGridViewアイテムの適切な解決策は、次のように拡張RelativeLayoutまたはLinearLayoutオーバーライドするonMeasureことです。
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
答えるのが遅いかもしれませんが、それでも、それは新しい訪問者に役立ちます。
Android Studio 2.3で導入された新しいConstraintLayoutにより、レスポンシブレイアウトの構築が非常に簡単になりました。
親のConstraintLayoutで、子のビュー/レイアウトを動的に正方形にするには、この属性を追加します
app:layout_constraintDimensionRatio="w,1:1"
wは幅方向の制約を指定し、1:1の比率で正方形のレイアウトを保証します。
xmlには、widthプロパティとheightプロパティをリンクできるものは何もありません。おそらく最も簡単なことは、サブクラス化LinearLayoutしてオーバーライドすることですonMeasure
@Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int size = width > height ? height : width;
setMeasuredDimension(size, size);
}
以前はこれを使用して、常に正方形のビューを作成しました。それでも動作するはずLinearLayoutです。
これを行うのに役立つ詳細情報:http : //developer.android.com/guide/topics/ui/custom-components.html http://developer.android.com/reference/android/view/View.MeasureSpec.html
super.onMeasure(widthMeasureSpec, widthMeasureSpec);!
super.onMeasure(widthMeasureSpec, widthMeasureSpec);すると正方形が得られますが、常に幅x幅です。与えられた測定値が高さよりも広い場合、問題が発生します。私のソリューションでは、2つの測定値のうち小さい方を使用するため、指定された長方形内に収まる最大の正方形が常に得られます。
私はこのようにしました:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int size;
if(widthMode == MeasureSpec.EXACTLY && widthSize > 0){
size = widthSize;
}
else if(heightMode == MeasureSpec.EXACTLY && heightSize > 0){
size = heightSize;
}
else{
size = widthSize < heightSize ? widthSize : heightSize;
}
int finalMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
super.onMeasure(finalMeasureSpec, finalMeasureSpec);
}
この実装では、幅と高さの間のサイズが小さいと仮定すると、レイアウトは正方形になります。また、LinearLayout内で重みを使用するなど、動的な値で設定することもできます。
非常に簡単な方法でそれを行うことができます-2super.onMeasure()回呼び出すだけです。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
int squareLen = Math.min(width, height);
super.onMeasure(
MeasureSpec.makeMeasureSpec(squareLen, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(squareLen, MeasureSpec.EXACTLY));
}
super.onMeasure()2回呼び出すと、描画プロセスの効率は低下しますが、他の回答が引き起こす可能性のあるレイアウトの問題を修正する簡単な方法です。
super.onMeasure()2回呼び出すと、ビューの新しいサイズを指定してレイアウトが正しく行われるようになります。これがないと、別の方法でレイアウトをトリガーするか、誤ったレイアウトを処理する必要があります。
それは次のように簡単です:
public class SquareRelativeLayout extends RelativeLayout {
public SquareRelativeLayout(Context context) {
super(context);
}
public SquareRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (widthMeasureSpec < heightMeasureSpec)
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
else
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
}
}
ビューまたはビューグループに設定できるすべてのレイアウトパラメータで機能するソリューションは次のとおりです。
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int widthDesc = MeasureSpec.getMode(widthMeasureSpec);
int heightDesc = MeasureSpec.getMode(heightMeasureSpec);
int size = 0;
if (widthDesc == MeasureSpec.UNSPECIFIED
&& heightDesc == MeasureSpec.UNSPECIFIED) {
size = DP(defaultSize); // Use your own default size, in our case
// it's 125dp
} else if ((widthDesc == MeasureSpec.UNSPECIFIED || heightDesc == MeasureSpec.UNSPECIFIED)
&& !(widthDesc == MeasureSpec.UNSPECIFIED && heightDesc == MeasureSpec.UNSPECIFIED)) {
//Only one of the dimensions has been specified so we choose the dimension that has a value (in the case of unspecified, the value assigned is 0)
size = width > height ? width : height;
} else {
//In all other cases both dimensions have been specified so we choose the smaller of the two
size = width > height ? height : width;
}
setMeasuredDimension(size, size);
乾杯
私の提案は、FrameLayoutから継承するカスタムレイアウトクラスを作成することです。OnMeasure()メソッドをオーバーライドし、SquareFrameLayout内に正方形にしたいコントロールを配置します。
これは、Xamarin.Androidで行われる方法です。
public class SquareFrameLayout : FrameLayout
{
private const string _tag = "SquareFrameLayout";
public SquareFrameLayout(Android.Content.Context context):base(context) {}
public SquareFrameLayout(IntPtr javaReference, Android.Runtime.JniHandleOwnership transfer):base(javaReference, transfer) {}
public SquareFrameLayout(Android.Content.Context context, IAttributeSet attrs):base(context, attrs) {}
public SquareFrameLayout(Android.Content.Context context, IAttributeSet attrs, int defStyleAttr):base(context, attrs, defStyleAttr) {}
public SquareFrameLayout(Android.Content.Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes):base(context, attrs, defStyleAttr, defStyleRes) {}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
var widthMode = MeasureSpec.GetMode(widthMeasureSpec);
int widthSize = MeasureSpec.GetSize(widthMeasureSpec);
var heightMode = MeasureSpec.GetMode(heightMeasureSpec);
int heightSize = MeasureSpec.GetSize(heightMeasureSpec);
int width, height;
switch (widthMode)
{
case MeasureSpecMode.Exactly:
width = widthSize;
break;
case MeasureSpecMode.AtMost:
width = Math.Min(widthSize, heightSize);
break;
default:
width = 100;
break;
}
switch (heightMode)
{
case MeasureSpecMode.Exactly:
height = heightSize;
break;
case MeasureSpecMode.AtMost:
height = Math.Min(widthSize, heightSize);
break;
default:
height = 100;
break;
}
Log.Debug(_tag, $"OnMeasure({widthMeasureSpec}, {heightMeasureSpec}) => Width mode: {widthMode}, Width: {widthSize}/{width}, Height mode: {heightMode}, Height: {heightSize}/{height}");
var size = Math.Min(width, height);
var newMeasureSpec = MeasureSpec.MakeMeasureSpec(size, MeasureSpecMode.Exactly);
base.OnMeasure(newMeasureSpec, newMeasureSpec);
}
}
ビュー(またはその他のコントロール)を正方形(および中央)にしたい場合は、次の方法でレイアウトに追加します。
<your.namespace.SquareFrameLayout
android:id="@+id/squareContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
<View
android:id="@+id/squareContent"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</your.namespace.SquareFrameLayout>
XMLに次の行を追加します。
app:layout_constraintDimensionRatio="1:1"
さまざまなレイアウトのラッパークラスを提供するAndroidライブラリであるSquareLayoutをチェックして、コア機能を失うことなく、それらを2乗次元でレンダリングします。
寸法はレイアウトがレンダリングされる直前に計算され、したがって、ビューが得られた後に調整するなどの一切再レンダリングまたは何でもありません。
ライブラリを使用するには、これをbuild.gradleに追加します。
repositories {
maven {
url "https://maven.google.com"
}
}
dependencies {
compile 'com.github.kaushikthedeveloper:squarelayout:0.0.3'
}
必要なのはSquareLinearLayoutです。
Kotlinで解決策を求めている人のために、これが私が行ったことFrameLayoutです。
package your.package.name
import android.content.Context
import android.util.AttributeSet
import android.widget.FrameLayout
class SquareLayout: FrameLayout {
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
if (widthMeasureSpec < heightMeasureSpec)
super.onMeasure(widthMeasureSpec, widthMeasureSpec)
else
super.onMeasure(heightMeasureSpec, heightMeasureSpec)
}
}
このコードを試してください:
public class SquareRelativeLayout extends RelativeLayout {
public SquareRelativeLayout(Context context) {
super(context);
}
public SquareRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int size;
if (widthMode == MeasureSpec.EXACTLY && widthSize > 0) {
size = widthSize;
} else if (heightMode == MeasureSpec.EXACTLY && heightSize > 0) {
size = heightSize;
} else {
size = widthSize < heightSize ? widthSize : heightSize;
}
int finalMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
super.onMeasure(finalMeasureSpec, finalMeasureSpec);
}
}