gpt4 book ai didi

java - 如何克服 ConstraintLayout 准则导致的别名问题?

转载 作者:行者123 更新时间:2023-11-29 23:25:58 25 4
gpt4 key购买 nike

我试图调和以下两件事:

A) 我想要一个精确、统一、干净的 UI,其中有几个大小相同的按钮,这些按钮与底层的“网格单元”完全对应——一个在尽可能多的情况下看起来尽可能相似(与屏幕尺寸成比例)的 UI尽可能使用 Android 设备。

B) 在 Android 上,用户设备的屏幕尺寸(纵横比和实际像素数)直到运行时(对应用而言)都是未知的。

我的解决方案是:(下面有一个代码示例!)

1) 将应用锁定为纵向模式,

2) 不要用静态/绝对术语定义任何东西,如 dp、px 等,而是概念化一个“基本度量单位”,它是屏幕高度的函数——在我的例子中是 0.08%——并以一切为基础关闭那个。

3) 在 ConstraintLayout 中设置水平指南,其位置表示为父(屏幕)高度的百分比。

4) 通过将它们的 XML layout_constraintDimensionRatio 属性设置为“1:1”并使用上述指南(参见第 3 步),使所有按钮都使用这个“基本单位”作为它们的高度和宽度,

5) 通过使用这些准则、父级边界或屏幕宽度 50% 处的另一条垂直准则的约束,完成所有 View 的定位和尺寸。

问题在于,取决于屏幕的像素高度(无论是奇数还是偶数......或者其他因素), View /按钮的尺寸(以及绘制在其中的路径)一对指南之间的约束与在另一对指南之间绘制的另一个 View 的约束不完全匹配......即使两对指南之间的距离应该是 parent 高度的相同百分比。 :)

下面是一个显示 Nexus 4 模拟器的例子:

enter image description here

起初我认为问题仅仅是由于 Android 的尺寸计算过程中的舍入“错误”,但为什么 View 不是正方形的,即使规定了 1:1 的比例属性?

我能想到的唯一解决方案是:

A) 以编程方式而不是使用 XML 进行布局...并将指南位置设置为精确的像素位置而不是百分比,然后回答问题“0.08 x 屏幕高度是多少?”我自己...进行适当的更正以补偿“不可分割”的屏幕高度。

B) 覆盖自定义 View 中的 onLayout() 并“强制”它们的尺寸保持一致……但这会违背指南的目的。 :(

但我真的希望有比 A 或 B 更简单的解决方案。

(我知道有人会建议使用 GridLayout,但这不是一个选项,原因有几个……其中之一是在 GridLayout 中,单元格内的 View 必须设置为 wrap_content……这意味着它们的路径无法在运行时生成相对于父级的绘制)。

不过,感谢任何其他建议。

代码示例:

我在下面创建了一个简单的“最小示例”,它应该很容易在 Android Studio 中重构。如果问题不是很明显,日志将揭示问题。

XML 布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="@+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">


<android.support.constraint.Guideline
android:id="@+id/guidelineHorizontalTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.08" />

<android.support.constraint.Guideline
android:id="@+id/guidelineHorizontalBottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.92" />

<android.support.constraint.Guideline
android:id="@+id/guidelineHorizontalCenter1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.38" />

<android.support.constraint.Guideline
android:id="@+id/guidelineHorizontalCenter2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.46" />

<android.support.constraint.Guideline
android:id="@+id/guidelineHorizontalCenter3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.54" />

<android.support.constraint.Guideline
android:id="@+id/guidelineHorizontalCenter4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.62" />

<com.example.boober.stack_aliasingproblem.CustomButton
android:id="@+id/buttonTopLeft"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonTopLeft"
app:layout_constraintBottom_toTopOf="@+id/guidelineHorizontalTop"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.example.boober.stack_aliasingproblem.CustomButton
android:id="@+id/buttonTopRight"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonTopRight"
app:layout_constraintBottom_toTopOf="@+id/guidelineHorizontalTop"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.example.boober.stack_aliasingproblem.CustomButton
android:id="@+id/buttonBottomLeft"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonBottomLeft"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guidelineHorizontalBottom" />

<com.example.boober.stack_aliasingproblem.CustomButton
android:id="@+id/buttonBottomRight"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonBottomRight"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/guidelineHorizontalBottom" />

<com.example.boober.stack_aliasingproblem.CustomButton
android:id="@+id/buttonMiddle"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonMiddle"
app:layout_constraintBottom_toBottomOf="@id/guidelineHorizontalCenter3"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/guidelineHorizontalCenter2" />

<com.example.boober.stack_aliasingproblem.CustomButton
android:id="@+id/buttonMiddleTopLeft"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonMiddleTopLeft"
app:layout_constraintBottom_toBottomOf="@id/guidelineHorizontalCenter2"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="@id/buttonMiddle"
app:layout_constraintTop_toTopOf="@id/guidelineHorizontalCenter1" />

<com.example.boober.stack_aliasingproblem.CustomButton
android:id="@+id/buttonMiddleTopRight"
android:layout_width="0dp"
android:layout_height="0dp"
android:tag="buttonMiddleTopRight"
app:layout_constraintBottom_toBottomOf="@id/guidelineHorizontalCenter2"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toEndOf="@id/buttonMiddle"
app:layout_constraintTop_toTopOf="@id/guidelineHorizontalCenter1" />
</android.support.constraint.ConstraintLayout>

主要 Activity .java:

public class MainActivity extends AppCompatActivity {

CustomButton buttonTopLeft;
CustomButton buttonTopRight;

CustomButton buttonMiddle;
CustomButton buttonMiddleTopLeft;
CustomButton getButtonMiddleTopRight;

CustomButton buttonBottomLeft;
CustomButton buttonBottomRight;

CustomButton[] arrayOfCustomButtons;

ConstraintLayout rootView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

buttonTopLeft = findViewById(R.id.buttonTopLeft);
buttonTopRight = findViewById(R.id.buttonTopRight);
buttonBottomLeft = findViewById(R.id.buttonBottomLeft);
buttonBottomRight = findViewById(R.id.buttonBottomRight);
buttonMiddle = findViewById(R.id.buttonMiddle);
buttonMiddleTopLeft = findViewById(R.id.buttonMiddleTopLeft);
getButtonMiddleTopRight = findViewById(R.id.buttonMiddleTopRight);

arrayOfCustomButtons = new CustomButton[]{buttonTopLeft, buttonTopRight, buttonBottomLeft,
buttonBottomRight, buttonMiddle, buttonMiddleTopLeft, getButtonMiddleTopRight};
rootView = findViewById(R.id.rootView);

for (final CustomButton cb : arrayOfCustomButtons) {
cb.setClickable(true);
cb.post(new Runnable() {
@Override
public void run() {
Log.i("XXX", "width of: " + cb.getTag() + " is: "
+ cb.getMeasuredWidth());
}
});
}

rootView.post(new Runnable() {
@Override
public void run() {
Log.i("XXX", "height of rootView is: " + rootView.getMeasuredHeight());
}
});
}

}

自定义按钮.java:

public class CustomButton extends View {

Path myOutlinePath;

Paint myThinPaintBrush;
Paint myThickPaintBrush;

boolean isHighlighted = false;

public CustomButton(Context context) {
super(context);
init();
}
public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public CustomButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);

float measuredWidth = getMeasuredWidth();

Log.i("XXX", "measured WIDTH Of " + this.getTag() + " is: " + measuredWidth);
Log.i("XXX", "measured HEIGT Of " + this.getTag() + " is: " + getMeasuredHeight());
Log.i("XXX", "\n ");

generateMyOutline(measuredWidth);

myThinPaintBrush.setStrokeWidth(measuredWidth/12);
myThickPaintBrush.setStrokeWidth(measuredWidth/6);

}

private void generateMyOutline(float W) {

Path path = new Path();

path.moveTo(0,0);
path.lineTo(W, 0);
path.lineTo(W, W);
path.lineTo(0, W);
path.lineTo(0,0);

myOutlinePath = path;

}

private void init() {

myOutlinePath = new Path();

myThinPaintBrush = new Paint();
myThinPaintBrush.setAntiAlias(false); // setting this to true does not solve the problem.
myThinPaintBrush.setStyle(Paint.Style.STROKE);
myThinPaintBrush.setStrokeCap(Paint.Cap.ROUND);

myThickPaintBrush = new Paint();
myThickPaintBrush.setAntiAlias(false);
myThickPaintBrush.setStyle(Paint.Style.STROKE);
myThickPaintBrush.setStrokeCap(Paint.Cap.ROUND);

}

@Override
public boolean onTouchEvent(MotionEvent event) {

if (this.isClickable()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isHighlighted = true;
invalidate();
break;

case MotionEvent.ACTION_UP:
isHighlighted = false;
invalidate();
break;

case MotionEvent.ACTION_CANCEL:
isHighlighted = false;
invalidate();
break;
}
}
return super.onTouchEvent(event);

}

@Override
protected void onDraw(Canvas canvas) {

canvas.drawPath(myOutlinePath, myThinPaintBrush);
if (isHighlighted) {
canvas.drawPath(myOutlinePath, myThickPaintBrush);
}
super.onDraw(canvas);

}

}

最佳答案

我会选择中间立场:按原样使用您的 XML 布局,并以编程方式对指南位置进行调整。以下代码通过计算新布局高度(初始布局高度的 8% 的倍数)将百分比准则转换为固定位置准则。

除底部方 block 往往较大外,所有尺寸均已正确计算。这可以根据您的实际要求轻松更正(更重要的是位于底部或与其他方 block 保持一定距离,例如。)

MainActivity.jav

public class MainActivity extends AppCompatActivity {

CustomButton buttonTopLeft;
CustomButton buttonTopRight;

CustomButton buttonMiddle;
CustomButton buttonMiddleTopLeft;
CustomButton getButtonMiddleTopRight;

CustomButton buttonBottomLeft;
CustomButton buttonBottomRight;

CustomButton[] arrayOfCustomButtons;

ConstraintLayout rootView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

buttonTopLeft = findViewById(R.id.buttonTopLeft);
buttonTopRight = findViewById(R.id.buttonTopRight);
buttonBottomLeft = findViewById(R.id.buttonBottomLeft);
buttonBottomRight = findViewById(R.id.buttonBottomRight);
buttonMiddle = findViewById(R.id.buttonMiddle);
buttonMiddleTopLeft = findViewById(R.id.buttonMiddleTopLeft);
getButtonMiddleTopRight = findViewById(R.id.buttonMiddleTopRight);

rootView = findViewById(R.id.rootView);

rootView.post(new Runnable() {
@Override
public void run() {
int rootViewHeight = rootView.getMeasuredHeight();
Log.i("XXX", "height of rootView is: " + rootViewHeight);
int segHeight = (int) (rootViewHeight * 0.08f);
adjustGuideline(R.id.guidelineHorizontalTop, segHeight);
adjustGuideline(R.id.guidelineHorizontalCenter1, segHeight);
adjustGuideline(R.id.guidelineHorizontalCenter2, segHeight);
adjustGuideline(R.id.guidelineHorizontalCenter3, segHeight);
adjustGuideline(R.id.guidelineHorizontalCenter4, segHeight);
adjustGuideline(R.id.guidelineHorizontalBottom, segHeight);

arrayOfCustomButtons = new CustomButton[]{buttonTopLeft, buttonTopRight, buttonBottomLeft,
buttonBottomRight, buttonMiddle, buttonMiddleTopLeft, getButtonMiddleTopRight};
rootView = findViewById(R.id.rootView);
for (final CustomButton cb : arrayOfCustomButtons) {
cb.setClickable(true);
cb.post(new Runnable() {
@Override
public void run() {
Log.i("MainActivity", "<<<< width of: " + cb.getTag() + " is: "
+ cb.getMeasuredWidth());
}
});
}
}
});
}

private void adjustGuideline(int guideLineId, int segHeight) {
Guideline gl = (Guideline) findViewById(guideLineId);
ConstraintLayout.LayoutParams lp = ((ConstraintLayout.LayoutParams) gl.getLayoutParams());
gl.setGuidelineBegin((int) (segHeight * lp.guidePercent / 0.08f));
gl.setGuidelinePercent(-1f);
}
}

关于java - 如何克服 ConstraintLayout 准则导致的别名问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53570805/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com