我在使用custom Square Layout
时偶然发现了这个问题:通过扩展布局并覆盖其onMeasure()
方法,使尺寸=两个中的较小者(高度或宽度) )。
以下是自定义布局代码:
public class CustomSquareLayout extends RelativeLayout{
public CustomSquareLayout(Context context) {
super(context);
}
public CustomSquareLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomSquareLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public CustomSquareLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Width is smaller
if(widthMeasureSpec < heightMeasureSpec)
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
//Height is smaller
else
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
}
}
自定义Square Layout工作正常,直到自定义布局变为超出界限的情况。应该有什么应该自动调整到屏幕尺寸,但不会发生。如下所示,CustomSquareLayout
实际上延伸到屏幕下方(不可见)。我期望onMeasure
能够处理这个问题并给出适当的测量结果。但事实并非如此。 感兴趣的注意事项这里是即使CustomSquareLayout
表现得很奇怪,它的子布局都属于方形布局,总是放在左手边。
<!-- XML for above image -->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="300dp"
android:text="Below is the Square Layout"
android:gravity="center"
android:id="@+id/text"
/>
<com.app.application.CustomSquareLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/text"
android:background="@color/colorAccent" #PINK
android:layout_centerInParent="true"
android:id="@+id/square"
android:padding="16dp"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" #Note this
android:background="@color/colorPrimaryDark" #BLUE
>
</RelativeLayout>
</com.app.application.CustomSquareLayout>
</RelativeLayout>
正常情况:( Textview在顶部)
以下是我引用的几个链接:
希望在扩展布局时使用onMeasure
或任何其他功能找到解决方法(即使某些扩展自定义布局,仍保留Square属性)
编辑2:我优先考虑onMeasure()
或类似功能,因为需要更早地(在渲染之前)确定布局规格(尺寸)。否则,在组件加载后更改尺寸很简单,但不要求。
答案 0 :(得分:7)
您可以通过在布局后检查“方形”来强制方形视图。将以下代码添加到onCreate()
。
final View squareView = findViewById(R.id.square);
squareView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
squareView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
if (squareView.getWidth() != squareView.getHeight()) {
int squareSize = Math.min(squareView.getWidth(), squareView.getHeight());
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) squareView.getLayoutParams();
lp.width = squareSize;
lp.height = squareSize;
squareView.requestLayout();
}
}
});
这将强制重新测量和布局具有替换MATCH_PARENT
的指定大小的方形视图。不是很优雅,但它很有效。
您还可以在自定义视图中添加PreDraw
listener。
<强> onPreDraw 强>
boolean onPreDraw()
在即将绘制视图树时要调用的回调方法。此时,树中的所有视图都已经过测量并给出了一个框架。客户端可以使用它来调整其滚动边界,甚至可以在绘制之前请求新的布局。
返回true表示继续当前绘图传递,或返回false表示取消。
在自定义视图中的每个构造函数中添加对初始化方法的调用:
private void init() {
this.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (getWidth() != getHeight()) {
int squareSize = Math.min(getWidth(), getHeight());
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) getLayoutParams();
lp.width = squareSize;
lp.height = squareSize;
requestLayout();
return false;
}
return true;
}
});
}
XML可能如下所示:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="300dp"
android:gravity="center"
android:text="Below is the Square Layout" />
<com.example.squareview.CustomSquareLayout
android:id="@+id/square"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/text"
android:background="@color/colorAccent"
android:padding="16dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="@color/colorPrimaryDark" />
</com.example.squareview.CustomSquareLayout>
</RelativeLayout>
答案 1 :(得分:4)
视图测量宽度与视图宽度之间存在差异(高度相同)。 onMeasure
仅设置视图的测量尺寸。绘图过程中仍然有一个不同的部分限制了视图的实际尺寸,以便它们不会超出父视图。
如果我添加此代码:
final View square = findViewById(R.id.square);
square.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
System.out.println("measured width: " + square.getMeasuredWidth());
System.out.println("measured height: " + square.getMeasuredHeight());
System.out.println("actual width: " + square.getWidth());
System.out.println("actual height: " + square.getHeight());
}
});
我在日志中看到了这一点:
09-05 10:19:25.768 4591 4591 I System.out: measured width: 579 09-05 10:19:25.768 4591 4591 I System.out: measured height: 579 09-05 10:19:25.768 4591 4591 I System.out: actual width: 768 09-05 10:19:25.768 4591 4591 I System.out: actual height: 579
如何通过创建自定义视图来解决它?我不知道;我从未学过。但我确实知道如何解决它而不必编写任何Java代码:使用ConstraintLayout
。
ConstraintLayout支持儿童应该能够使用宽高比设置尺寸的想法,因此您可以简单地使用1
的比例并获得一个方形儿童。这是我的更新布局(关键部分是app:layout_constraintDimensionRatio
attr):
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="300dp"
android:gravity="center"
android:text="Below is the Square Layout"
app:layout_constraintTop_toTopOf="parent"/>
<RelativeLayout
android:id="@+id/square"
android:layout_width="match_parent"
android:layout_height="0dp"
android:padding="16dp"
android:background="@color/colorAccent"
app:layout_constraintTop_toBottomOf="@+id/text"
app:layout_constraintDimensionRatio="1">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="@color/colorPrimaryDark">
</RelativeLayout>
</RelativeLayout>
</android.support.constraint.ConstraintLayout>
截图:
答案 2 :(得分:1)
您无法比较两种测量规格,因为它们不仅仅是尺寸。您可以在this answer中看到非常好的解释。此答案适用于自定义视图,但测量规格相同。您需要获取模式和大小来计算最终尺寸,并比较两个尺寸的最终结果。
在您分享的第二个示例中,正确的问题是this one(第三个答案)。是用C#编写的Xamarin,但很容易理解。
您失败的情况是因为您正在寻找AT_MOST
模式(当视图触及屏幕底部时),这就是为什么在这种情况下比较失败的原因
这应该是最后的方法(可能包含错别字,我无法测试它:
@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 width, height;
switch (widthMode) {
case MeasureSpec.EXACTLY:
width = widthSize;
break;
case MeasureSpec.AT_MOST:
width = Math.min(widthSize, heightSize);
break;
default:
width = 100;
break;
}
switch (heightMode) {
case MeasureSpec.EXACTLY:
height = heightSize;
break;
case MeasureSpec.AT_MOST:
height = Math.min(widthSize, heightSize);
break;
default:
height = 100;
break;
}
var size = Math.min(width, height);
var newMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
super.onMeasure(newMeasureSpec, newMeasureSpec);
}
我希望最终结果大致相同(可能是居中,但这个维度):
请注意,这是使用Gimp完成的图像。
答案 3 :(得分:-1)
试试这个。您可以使用on measure方法创建自定义视图。请查看以下链接了解更多详情。
http://codecops.blogspot.in/2017/06/how-to-make-responsive-imageview-in.html