如何为ImageView
赋予六边形形状。有可能以同样的方式做吗?如果是,那怎么样。如果这不可能实现,那么如何实现呢?
<shape xmlns:android="http//schemas.android.com/apk/res/android"
android:shape="hexagon">
<solid android:color="#ffffffff" />
<size android:width="60dp"
android:height="40dp" />
</shape>
这里我不能做掩蔽图像,因为我无法检测到应该裁剪哪个位图部分以获得六边形形状位图。所以我正在寻找给ImageView
答案 0 :(得分:58)
试试此视图。您可能希望根据您的特定需求进行调整,但它会在视图顶部绘制带边框的六边形蒙版。后台资源低于掩码。
结果:
代码:
<强> HexagonMaskView.java 强>
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Path;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.View;
public class HexagonMaskView extends View {
private Path hexagonPath;
private Path hexagonBorderPath;
private float radius;
private float width, height;
private int maskColor;
public HexagonMaskView(Context context) {
super(context);
init();
}
public HexagonMaskView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public HexagonMaskView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
hexagonPath = new Path();
hexagonBorderPath = new Path();
maskColor = 0xFF01FF77;
}
public void setRadius(float r) {
this.radius = r;
calculatePath();
}
public void setMaskColor(int color) {
this.maskColor = color;
invalidate();
}
private void calculatePath() {
float triangleHeight = (float) (Math.sqrt(3) * radius / 2);
float centerX = width/2;
float centerY = height/2;
hexagonPath.moveTo(centerX, centerY + radius);
hexagonPath.lineTo(centerX - triangleHeight, centerY + radius/2);
hexagonPath.lineTo(centerX - triangleHeight, centerY - radius/2);
hexagonPath.lineTo(centerX, centerY - radius);
hexagonPath.lineTo(centerX + triangleHeight, centerY - radius/2);
hexagonPath.lineTo(centerX + triangleHeight, centerY + radius/2);
hexagonPath.moveTo(centerX, centerY + radius);
float radiusBorder = radius - 5;
float triangleBorderHeight = (float) (Math.sqrt(3) * radiusBorder / 2);
hexagonBorderPath.moveTo(centerX, centerY + radiusBorder);
hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY + radiusBorder/2);
hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY - radiusBorder/2);
hexagonBorderPath.lineTo(centerX, centerY - radiusBorder);
hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY - radiusBorder/2);
hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY + radiusBorder/2);
hexagonBorderPath.moveTo(centerX, centerY + radiusBorder);
invalidate();
}
@Override
public void onDraw(Canvas c){
super.onDraw(c);
c.clipPath(hexagonBorderPath, Region.Op.DIFFERENCE);
c.drawColor(Color.WHITE);
c.save();
c.clipPath(hexagonPath, Region.Op.DIFFERENCE);
c.drawColor(maskColor);
c.save();
}
// getting the view size and default radius
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
radius = height / 2 - 10;
calculatePath();
}
}
更新29.07.2016
更好的方法是仅剪切源图像而不绘制整个视图的背景。切换到ImageView作为基类以受益于scaleType。我也做了一些代码重构。
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.Region;
import android.util.AttributeSet;
import android.widget.ImageView;
public class HexagonMaskView extends ImageView {
private Path hexagonPath;
private Path hexagonBorderPath;
private Paint mBorderPaint;
public HexagonMaskView(Context context) {
super(context);
init();
}
public HexagonMaskView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public HexagonMaskView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
this.hexagonPath = new Path();
this.hexagonBorderPath = new Path();
this.mBorderPaint = new Paint();
this.mBorderPaint.setColor(Color.WHITE);
this.mBorderPaint.setStrokeCap(Paint.Cap.ROUND);
this.mBorderPaint.setStrokeWidth(50f);
this.mBorderPaint.setStyle(Paint.Style.STROKE);
}
public void setRadius(float radius) {
calculatePath(radius);
}
public void setBorderColor(int color) {
this.mBorderPaint.setColor(color);
invalidate();
}
private void calculatePath(float radius) {
float halfRadius = radius / 2f;
float triangleHeight = (float) (Math.sqrt(3.0) * halfRadius);
float centerX = getMeasuredWidth() / 2f;
float centerY = getMeasuredHeight() / 2f;
this.hexagonPath.reset();
this.hexagonPath.moveTo(centerX, centerY + radius);
this.hexagonPath.lineTo(centerX - triangleHeight, centerY + halfRadius);
this.hexagonPath.lineTo(centerX - triangleHeight, centerY - halfRadius);
this.hexagonPath.lineTo(centerX, centerY - radius);
this.hexagonPath.lineTo(centerX + triangleHeight, centerY - halfRadius);
this.hexagonPath.lineTo(centerX + triangleHeight, centerY + halfRadius);
this.hexagonPath.close();
float radiusBorder = radius - 5f;
float halfRadiusBorder = radiusBorder / 2f;
float triangleBorderHeight = (float) (Math.sqrt(3.0) * halfRadiusBorder);
this.hexagonBorderPath.reset();
this.hexagonBorderPath.moveTo(centerX, centerY + radiusBorder);
this.hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY + halfRadiusBorder);
this.hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY - halfRadiusBorder);
this.hexagonBorderPath.lineTo(centerX, centerY - radiusBorder);
this.hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY - halfRadiusBorder);
this.hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY + halfRadiusBorder);
this.hexagonBorderPath.close();
invalidate();
}
@Override
public void onDraw(Canvas c) {
c.drawPath(hexagonBorderPath, mBorderPaint);
c.clipPath(hexagonPath, Region.Op.INTERSECT);
c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
super.onDraw(c);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
calculatePath(Math.min(width / 2f, height / 2f) - 10f);
}
}
示例布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:background="@android:color/holo_green_dark">
<com.scelus.hexagonmaskimproved.HexagonMaskView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/bear"
android:background="@android:color/holo_green_light"/>
</RelativeLayout>
答案 1 :(得分:7)
以下是我的工作代码,它支持阴影:
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class HexagonImageView extends ImageView {
private Path hexagonPath;
private Path hexagonBorderPath;
private float radius;
private Bitmap image;
private int viewWidth;
private int viewHeight;
private Paint paint;
private BitmapShader shader;
private Paint paintBorder;
private int borderWidth = 4;
public HexagonImageView(Context context) {
super(context);
setup();
}
public HexagonImageView(Context context, AttributeSet attrs) {
super(context, attrs);
setup();
}
public HexagonImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setup();
}
private void setup() {
paint = new Paint();
paint.setAntiAlias(true);
paintBorder = new Paint();
setBorderColor(Color.WHITE);
paintBorder.setAntiAlias(true);
this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
paintBorder.setShadowLayer(4.0f, 1.0f, 1.0f, Color.BLACK);
hexagonPath = new Path();
hexagonBorderPath = new Path();
}
public void setRadius(float r) {
this.radius = r;
calculatePath();
}
public void setBorderWidth(int borderWidth) {
this.borderWidth = borderWidth;
this.invalidate();
}
public void setBorderColor(int borderColor) {
if (paintBorder != null)
paintBorder.setColor(borderColor);
this.invalidate();
}
private void calculatePath() {
float triangleHeight = (float) (Math.sqrt(3) * radius / 2);
float centerX = viewWidth/2;
float centerY = viewHeight/2;
hexagonBorderPath.moveTo(centerX, centerY + radius);
hexagonBorderPath.lineTo(centerX - triangleHeight, centerY + radius/2);
hexagonBorderPath.lineTo(centerX - triangleHeight, centerY - radius/2);
hexagonBorderPath.lineTo(centerX, centerY - radius);
hexagonBorderPath.lineTo(centerX + triangleHeight, centerY - radius/2);
hexagonBorderPath.lineTo(centerX + triangleHeight, centerY + radius/2);
hexagonBorderPath.moveTo(centerX, centerY + radius);
float radiusBorder = radius - borderWidth;
float triangleBorderHeight = (float) (Math.sqrt(3) * radiusBorder / 2);
hexagonPath.moveTo(centerX, centerY + radiusBorder);
hexagonPath.lineTo(centerX - triangleBorderHeight, centerY + radiusBorder/2);
hexagonPath.lineTo(centerX - triangleBorderHeight, centerY - radiusBorder/2);
hexagonPath.lineTo(centerX, centerY - radiusBorder);
hexagonPath.lineTo(centerX + triangleBorderHeight, centerY - radiusBorder/2);
hexagonPath.lineTo(centerX + triangleBorderHeight, centerY + radiusBorder/2);
hexagonPath.moveTo(centerX, centerY + radiusBorder);
invalidate();
}
private void loadBitmap() {
BitmapDrawable bitmapDrawable = (BitmapDrawable) this.getDrawable();
if (bitmapDrawable != null)
image = bitmapDrawable.getBitmap();
}
@SuppressLint("DrawAllocation")
@Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
loadBitmap();
// init shader
if (image != null) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvas.getWidth(), canvas.getHeight(), false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
canvas.drawPath(hexagonBorderPath, paintBorder);
canvas.drawPath(hexagonPath, paint);
}
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec, widthMeasureSpec);
viewWidth = width - (borderWidth * 2);
viewHeight = height - (borderWidth * 2);
radius = height / 2 - borderWidth;
calculatePath();
setMeasuredDimension(width, height);
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
}
else {
result = viewWidth;
}
return result;
}
private int measureHeight(int measureSpecHeight, int measureSpecWidth) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
}
else {
result = viewHeight;
}
return (result + 2);
}
}
答案 2 :(得分:4)
请参阅这个创建三角形的示例,以便从中获取逻辑:)
http://looksok.wordpress.com/2013/08/24/android-triangle-arrow-defined-as-an-xml-shape/
我找到的另一种解决方案但未经过测试,请尝试此操作
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView tv = (TextView) findViewById(R.id.text);
Path path = new Path();
float stdW = 100;
float stdH = 100;
float w3 = stdW / 3;
float h2 = stdH / 2;
path.moveTo(0, h2);
h2 -= 6 / 2;
path.rLineTo(w3, -h2); path.rLineTo(w3, 0); path.rLineTo(w3, h2);
path.rLineTo(-w3, h2); path.rLineTo(-w3, 0); path.rLineTo(-w3, -h2);
Shape s = new PathShape(path, stdW, stdH);
ShapeDrawable d = new ShapeDrawable(s);
Paint p = d.getPaint();
p.setColor(0xffeeeeee);
p.setStyle(Style.STROKE);
p.setStrokeWidth(6);
tv.setBackgroundDrawable(d);
}
来源:Google group
第三种解决方案 - 这可能是有用的库
PathDrawable是一个Drawable,它使用Path对象绘制简单的形状。
答案 3 :(得分:4)
您可以尝试以下几种方法:
您可能想尝试在图片顶部绘制一个9patch。
Romain Guy还有这个短暂的tuto:http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/
BitmapShader shader;
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(shader);
RectF rect = new RectF(0.0f, 0.0f, width, height);
// rect contains the bounds of the shape
// radius is the radius in pixels of the rounded corners
// paint contains the shader that will texture the shape
canvas.drawRoundRect(rect, radius, radius, paint);
您可以尝试使用drawRoundRect()
来获得所需的形状,而不是使用drawPath()
画布方法。
希望这会让你朝着正确的方向前进。
答案 4 :(得分:3)
回复已经晚了..但希望它会帮助别人......
public Bitmap getHexagonShape(Bitmap scaleBitmapImage) {
// TODO Auto-generated method stub
int targetWidth = 200;
int targetHeight =200;
Bitmap targetBitmap = Bitmap.createBitmap(targetWidth,
targetHeight,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(targetBitmap);
Path path = new Path();
float stdW = 200;
float stdH = 200;
float w3 =stdW / 2;
float h2 = stdH / 2;
float radius=stdH/2-10;
float triangleHeight = (float) (Math.sqrt(3) * radius / 2);
float centerX = stdW/2;
float centerY = stdH/2;
path.moveTo(centerX, centerY + radius);
path.lineTo(centerX - triangleHeight, centerY + radius/2);
path.lineTo(centerX - triangleHeight, centerY - radius/2);
path.lineTo(centerX, centerY - radius);
path.lineTo(centerX + triangleHeight, centerY - radius/2);
path.lineTo(centerX + triangleHeight, centerY + radius/2);
path.moveTo(centerX, centerY + radius);
canvas.clipPath(path);
Bitmap sourceBitmap = scaleBitmapImage;
canvas.drawBitmap(sourceBitmap,
new Rect(0, 0, sourceBitmap.getWidth(),
sourceBitmap.getHeight()),
new Rect(0, 0, targetWidth,
targetHeight), null);
return targetBitmap;
}
public static Bitmap drawableToBitmap (Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable)drawable).getBitmap();
}
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
在您想要使用的地方调用
Drawable drawable = getResources().getDrawable( R.drawable.placeholder );
Bitmap b=getHexagonShape(drawableToBitmap(drawable));
img=(ImageView)findViewById(R.id.imageView);
img.setImageBitmap(b);
答案 5 :(得分:1)
下面的函数将您的图像作为输入位图读取并返回一个六边形的位图
public Bitmap getHexagonShape(Bitmap scaleBitmapImage) {
// TODO Auto-generated method stub
int targetWidth = 600;
int targetHeight = 600;
Bitmap targetBitmap = Bitmap.createBitmap(targetWidth,
targetHeight,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(targetBitmap);
Path path = new Path();
float stdW = 300;
float stdH = 300;
float w3 =stdW / 2;
float h2 = stdH / 2;
path.moveTo(0, (float) (h2*Math.sqrt(3)/2));
path.rLineTo(w3/2, -(float) (h2*Math.sqrt(3)/2)); path.rLineTo(w3, 0); path.rLineTo(w3/2, (float) (h2*Math.sqrt(3)/2));
path.rLineTo(-w3/2, (float) (h2*Math.sqrt(3)/2)); path.rLineTo(-w3, 0); path.rLineTo(-w3/2, -(float) (h2*Math.sqrt(3)/2));
canvas.clipPath(path);
Bitmap sourceBitmap = scaleBitmapImage;
canvas.drawBitmap(sourceBitmap,
new Rect(0, 0, sourceBitmap.getWidth(),
sourceBitmap.getHeight()),
new Rect(0, 0, targetWidth,
targetHeight), null);
return targetBitmap;
}
答案 6 :(得分:1)
我不知道OP是否得到了他正在寻找的答案,但现在就去了。
我已经创建了一个扩展ImageView的自定义视图,它可以为您完成更好的工作。 这里的答案只是在ImageView中创建一个mak并强制你将图片设置为背景
我的视图允许您将图像设置为标准位图,它可以处理CenterCrop和图像缩放。 它实际上将面具设置在外面,并使用相同的边框加上投影。
如果这还不够,您可以轻松创建自定义形状进行渲染,只需扩展RenderShape类。 (库中包含4种形状:圆形,三角形,六边形和八边形)
干杯
答案 7 :(得分:1)
我用这段代码解决了它:
private Bitmap getHexagoneCroppedBitmap(Bitmap bitmap, int radius) {
Bitmap finalBitmap;
if (bitmap.getWidth() != radius || bitmap.getHeight() != radius)
finalBitmap = Bitmap.createScaledBitmap(bitmap, radius, radius,
false);
else
finalBitmap = bitmap;
Bitmap output = Bitmap.createBitmap(finalBitmap.getWidth(),
finalBitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
Paint paint = new Paint();
final Rect rect = new Rect(0, 0, finalBitmap.getWidth(),
finalBitmap.getHeight());
Point point1_draw = new Point(75, 0);
Point point2_draw = new Point(0, 50);
Point point3_draw = new Point(0, 100);
Point point4_draw = new Point(75, 150);
Point point5_draw = new Point(150, 100);
Point point6_draw = new Point(150, 50);
Path path = new Path();
path.moveTo(point1_draw.x, point1_draw.y);
path.lineTo(point2_draw.x, point2_draw.y);
path.lineTo(point3_draw.x, point3_draw.y);
path.lineTo(point4_draw.x, point4_draw.y);
path.lineTo(point5_draw.x, point5_draw.y);
path.lineTo(point6_draw.x, point6_draw.y);
path.close();
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(finalBitmap, rect, rect, paint);
return output;
}
答案 8 :(得分:1)
您可以使用siamed的Android Shape ImageView。
https://github.com/siyamed/android-shape-imageview
<com.github.siyamed.shapeimageview.HexagonImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"
android:src="@drawable/neo"
app:siBorderWidth="8dp"
app:siBorderColor="@color/darkgray"/>
请阅读github上的文档,有很多选项。