我在我的 XML 布局中嵌入了 3 个相同的画布元素。不幸的是,Android 中的布局编辑器在布局中显示了错误的形状和错误的元素位置,这使得布局设计非常困难。
在这里,您可以看到布局编辑器中的内容:
在这里您可以看到 Android 模拟器中的输出:
有两件事很奇怪。
- 首先,在布局编辑器中,画布元素的形状没有正确显示。只显示了温度计的一小部分。XML 布局文件中画布元素的大小越小,分数就越小。
- 位置不对。您可以在布局编辑器中清楚地看到 3 个元素没有重叠,而在模拟器中它们重叠。
有谁知道为什么会发生这种情况以及如何解决这两个问题?
这是 XML 布局文件:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.nikhiljain.canvasdrawingsample.Thermometer
android:id="@+id/thermometer_1"
android:layout_width="122dp"
android:layout_height="130dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.546"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.912" />
<com.nikhiljain.canvasdrawingsample.Thermometer
android:id="@+id/thermometer_2"
android:layout_width="222dp"
android:layout_height="230dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.628" />
<com.nikhiljain.canvasdrawingsample.Thermometer
android:id="@+id/thermometer_3"
android:layout_width="322dp"
android:layout_height="330dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
这是画布元素的代码:
package com.nikhiljain.canvasdrawingsample;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class Thermometer extends View {
private Paint mInnerCirclePaint;
private int mInnerRadius;
private int mThermometerColor = Color.RED;
private Bitmap bitmap;
private int left;
private int top;
private int innerCircleCenter;
private int circleHeight;
private int lineEndY;
private int lineStartY;
public Thermometer(Context context) {
this(context, null);
}
public Thermometer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public Thermometer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (attrs != null) {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Thermometer, defStyle, 0);
mThermometerColor = a.getColor(R.styleable.Thermometer_therm_color, mThermometerColor);
a.recycle();
}
init();
}
private void init() {
mInnerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mInnerCirclePaint.setColor(mThermometerColor);
mInnerCirclePaint.setStyle(Paint.Style.FILL);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.thermometer_container);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// init bitmap
int scaledHeight;
int scaledWidth;
int width = getWidth();
int height = getHeight();
if (width > height) {
scaledHeight = (int) (height * 0.98);
scaledWidth = scaledHeight * bitmap.getWidth() / bitmap.getHeight();
} else {
scaledWidth = (int) (width * 0.98);
scaledHeight = scaledWidth * bitmap.getHeight() / bitmap.getWidth();
}
bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, true);
mInnerRadius = bitmap.getWidth() / 8;
mInnerCirclePaint.setStrokeWidth((int)(bitmap.getWidth() / 10));
left = (getWidth() - bitmap.getWidth()) / 2;
top = (int)(0.9 * getHeight() - bitmap.getHeight()) / 2;
innerCircleCenter = (left + left + bitmap.getWidth() + (Math.min(width, height) / 72)) / 2;
circleHeight = (top + bitmap.getHeight()) - (int)(bitmap.getHeight() / 4.6f);
Log.e("LogTag", "getHeight(): " + getHeight());
Log.e("LogTag", "bitmap.getHeight(): " + bitmap.getHeight());
//Parameter Values for lineStartY: 0.8=upper limit, 1.1=22 °C, 3.05=20 °C, 3.4=lower limit
lineStartY = (int)(4.4*((int)(bitmap.getHeight() / 4.6f) + top));
lineEndY = (int)(1.0* ((top + bitmap.getHeight()) - (int)(bitmap.getHeight() / 4f)));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawThermometer(canvas);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//takes care of paddingTop and paddingBottom
int paddingY = getPaddingBottom() + getPaddingTop();
//get height and width
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
height += paddingY;
setMeasuredDimension(width, height);
}
private void drawThermometer(Canvas canvas) {
canvas.drawCircle(innerCircleCenter, circleHeight, mInnerRadius, mInnerCirclePaint);
canvas.drawLine(innerCircleCenter, lineStartY, innerCircleCenter, lineEndY, mInnerCirclePaint);
canvas.drawBitmap(bitmap, left, top, new Paint());
}
public void setThermometerColor(int thermometerColor) {
this.mThermometerColor = thermometerColor;
mInnerCirclePaint.setColor(mThermometerColor);
invalidate();
}
}
提醒:有意见吗?