나는 GridView본질적으로 많은 뷰를 표시 하기 위해 사용하고 있습니다 LinearLayouts. 나는 LinearLayouts모두 정사각형이 되길 원하지만 동적으로 크기가 조정되기를 원합니다 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 너비입니다. 주어진 치수가 키보다 넓 으면 문제가 발생합니다. 내 솔루션은 두 측정 중 더 작은 것을 사용하므로 항상 주어진 직사각형에 맞는 가장 큰 정사각형을 얻습니다.
나는 이렇게했다 :
@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 내부에서 가중치를 사용하는 것과 같이 동적 값으로 설정할 수도 있습니다.
아주 간단한 방법으로 할 수 있습니다 super.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()두 번 호출 하면 그리기 프로세스 측면에서 효율성이 떨어지지 만 다른 답변으로 인해 발생할 수있는 레이아웃 문제를 해결하는 간단한 방법입니다.
super.onMeasure()두 번 호출 하면 뷰의 새로운 크기가 주어지면 레이아웃이 올바르게 수행됩니다. 이것이 없으면 다른 방식으로 레이아웃을 트리거하거나 잘못된 레이아웃을 처리해야합니다.
다음과 같이 간단합니다.
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"
확인 SquareLayout , 안드로이드 라이브러리다양한 레이아웃에 대한 래퍼 클래스를 제공 인 핵심 기능을 잃지 않고 Squared 차원으로 렌더링합니다.
치수는 단지 레이아웃이 렌더링되기 전에 계산 , 따라서보기를 얻을되면 조정하는 등 더 재 렌더링 또는 아무것도 없다.
라이브러리를 사용하려면 다음을 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);
}
}