使用 ImageView 自定义可绘制对象
Custom drawable with ImageView
我已经有一个 'ImageView' 具有这些参数:
android:layout_width="wrap_content"
android:layout_height="wrap_content"
并设置自定义 Drawable
:
public class HexDrawable extends Drawable {
private Path hexagonPath;
private float mWidth, mHeight;
private int mBackgroundColor;
private int mStrokeColor;
private int mStrokeWidth;
public HexDrawable(){
init();
}
public void setBackgroundColor(int color) {
mBackgroundColor = color;
}
public void setStrokeWidth(int width) {
mStrokeWidth = width;
}
public void setStrokeColor(int color) {
mStrokeColor = color;
}
@Override
public int getIntrinsicHeight() {
return 60;
}
@Override
public int getIntrinsicWidth() {
return 60;
}
private void init() {
hexagonPath = new Path();
mBackgroundColor = Color.BLUE;
mStrokeColor = Color.GREEN;
mStrokeWidth = 4;
}
private void calculatePath() {
float p = mStrokeWidth / 2;
float w = mWidth - 2 * p;
float h = mHeight - 2 * p;
float r = h / 2;
float a = (float) (r / Math.sqrt(3));
PointF X = new PointF(p + a + r / 2, p);
PointF Y = new PointF(p + a + r , p);
PointF A = new PointF(p + a, p + 0f);
PointF B = new PointF(p + 0f, p + r);
PointF C = new PointF(p + a, p + 2 * r);
PointF D = new PointF(p + w - a, p + 2 * r);
PointF E = new PointF(p + w, p + r);
PointF F = new PointF(p + w - a, p + 0);
hexagonPath.moveTo(Y.x, Y.y);
hexagonPath.lineTo(A.x, A.y);
hexagonPath.lineTo(B.x, B.y);
hexagonPath.lineTo(C.x, C.y);
hexagonPath.lineTo(D.x, D.y);
hexagonPath.lineTo(E.x, E.y);
hexagonPath.lineTo(F.x, F.y);
hexagonPath.lineTo(X.x, X.y);
}
@Override
protected void onBoundsChange(Rect bounds) {
mWidth = bounds.width();
mHeight = bounds.height();
calculatePath();
}
@Override
public void draw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(mStrokeColor); // set the color
paint.setStrokeWidth(mStrokeWidth); // set the size
paint.setDither(true); // set the dither to true
paint.setStyle(Paint.Style.STROKE); // set to STOKE
paint.setStrokeJoin(Paint.Join.ROUND); // set the join to round you want
paint.setStrokeCap(Paint.Cap.ROUND); // set the paint cap to round too
paint.setPathEffect(new CornerPathEffect(mStrokeWidth)); // set the path effect when they join.
paint.setAntiAlias(true);
canvas.drawPath(hexagonPath, paint);
canvas.clipPath(hexagonPath, Region.Op.INTERSECT);
canvas.drawColor(mBackgroundColor);
canvas.drawPath(hexagonPath, paint);
canvas.save();
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return 0;
}
}
似乎 ImageView
在这种情况下使用所有宽度。
如何正确实施 Drawable
以与 ImageView
一起使用?
您的代码完全正确:
这是我填写 ImageView
的方式(在 activity 的 onCreate()
中):
((ImageView)findViewById(R.id.hexImageView)).setImageDrawable(new HexDrawable());
屏幕截图中 Activity
的布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<ImageView
android:id="@+id/hexImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
如果我用值替换 wrap_content
,六边形会按预期改变其大小。
在 Android 6.0 和 4.3 上测试。
只有一个提示 - 与其在 getIntrinsicHeight()
和 getIntrinsicWidth()
中硬编码值,不如使用 dimens
可能更好。
问题的根源在于剪辑模式。
最好用canvas.clipPath(hexagonPath, Region.Op.REPLACE);
此外,问题示例在 ImageView 中运行良好,但经过深入调查后我明白,在 android 5.0 及更高版本中,此可绘制对象在 TextView
中的 drawableLeft 处使用。
它也不需要覆盖 getIntrinsicHeight
我已经有一个 'ImageView' 具有这些参数:
android:layout_width="wrap_content"
android:layout_height="wrap_content"
并设置自定义 Drawable
:
public class HexDrawable extends Drawable {
private Path hexagonPath;
private float mWidth, mHeight;
private int mBackgroundColor;
private int mStrokeColor;
private int mStrokeWidth;
public HexDrawable(){
init();
}
public void setBackgroundColor(int color) {
mBackgroundColor = color;
}
public void setStrokeWidth(int width) {
mStrokeWidth = width;
}
public void setStrokeColor(int color) {
mStrokeColor = color;
}
@Override
public int getIntrinsicHeight() {
return 60;
}
@Override
public int getIntrinsicWidth() {
return 60;
}
private void init() {
hexagonPath = new Path();
mBackgroundColor = Color.BLUE;
mStrokeColor = Color.GREEN;
mStrokeWidth = 4;
}
private void calculatePath() {
float p = mStrokeWidth / 2;
float w = mWidth - 2 * p;
float h = mHeight - 2 * p;
float r = h / 2;
float a = (float) (r / Math.sqrt(3));
PointF X = new PointF(p + a + r / 2, p);
PointF Y = new PointF(p + a + r , p);
PointF A = new PointF(p + a, p + 0f);
PointF B = new PointF(p + 0f, p + r);
PointF C = new PointF(p + a, p + 2 * r);
PointF D = new PointF(p + w - a, p + 2 * r);
PointF E = new PointF(p + w, p + r);
PointF F = new PointF(p + w - a, p + 0);
hexagonPath.moveTo(Y.x, Y.y);
hexagonPath.lineTo(A.x, A.y);
hexagonPath.lineTo(B.x, B.y);
hexagonPath.lineTo(C.x, C.y);
hexagonPath.lineTo(D.x, D.y);
hexagonPath.lineTo(E.x, E.y);
hexagonPath.lineTo(F.x, F.y);
hexagonPath.lineTo(X.x, X.y);
}
@Override
protected void onBoundsChange(Rect bounds) {
mWidth = bounds.width();
mHeight = bounds.height();
calculatePath();
}
@Override
public void draw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(mStrokeColor); // set the color
paint.setStrokeWidth(mStrokeWidth); // set the size
paint.setDither(true); // set the dither to true
paint.setStyle(Paint.Style.STROKE); // set to STOKE
paint.setStrokeJoin(Paint.Join.ROUND); // set the join to round you want
paint.setStrokeCap(Paint.Cap.ROUND); // set the paint cap to round too
paint.setPathEffect(new CornerPathEffect(mStrokeWidth)); // set the path effect when they join.
paint.setAntiAlias(true);
canvas.drawPath(hexagonPath, paint);
canvas.clipPath(hexagonPath, Region.Op.INTERSECT);
canvas.drawColor(mBackgroundColor);
canvas.drawPath(hexagonPath, paint);
canvas.save();
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return 0;
}
}
似乎 ImageView
在这种情况下使用所有宽度。
如何正确实施 Drawable
以与 ImageView
一起使用?
您的代码完全正确:
这是我填写 ImageView
的方式(在 activity 的 onCreate()
中):
((ImageView)findViewById(R.id.hexImageView)).setImageDrawable(new HexDrawable());
屏幕截图中 Activity
的布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<ImageView
android:id="@+id/hexImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
如果我用值替换 wrap_content
,六边形会按预期改变其大小。
在 Android 6.0 和 4.3 上测试。
只有一个提示 - 与其在 getIntrinsicHeight()
和 getIntrinsicWidth()
中硬编码值,不如使用 dimens
可能更好。
问题的根源在于剪辑模式。
最好用canvas.clipPath(hexagonPath, Region.Op.REPLACE);
此外,问题示例在 ImageView 中运行良好,但经过深入调查后我明白,在 android 5.0 及更高版本中,此可绘制对象在 TextView
中的 drawableLeft 处使用。
它也不需要覆盖 getIntrinsicHeight