Cómo dar forma hexagonal a ImageView

Cómo dar forma hexagonal a ImageView . ¿Es posible hacer de la misma manera? Si es así, ¿cómo? Si esto no es posible a través de esto, ¿cómo se puede lograr esto?

     

Captura de pantalla

enter image description here

Aquí no puedo hacer la imagen de enmascaramiento porque no puedo detectar qué parte del bitmap debería recortar para obtener un bitmap con forma hexagonal. Así que estoy buscando la respuesta para darle forma hexagonal a ImageView

Prueba esta vista. Es posible que desee ajustarlo para sus necesidades específicas, pero dibuja una máscara hexagonal con un borde en la parte superior de una vista. El recurso de fondo va debajo de la máscara.

El resultado:

enter image description here

El código:

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(); } } 

Actualización 29.07.2016

Una mejor manera de solo recortar la imagen de origen sin pintar el fondo de toda la vista. Cambiado a un ImageView como una clase base para beneficiarse del scaleType. También hice un código de refactorización.

 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); } } 

Diseño de ejemplo:

 < ?xml version="1.0" encoding="utf-8"?>    

Nuevo resultado

Aquí está mi código de trabajo para esto, admite sombras para:

 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); } } 

Hay un par de cosas que puedes probar:

  • Es posible que desee intentar dibujar un parche 9 en la parte superior de su imagen.

  • También hay un breve tutorial de Romain Guy: 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); 

    En lugar de utilizar el método drawRoundRect() del canvas, puede intentar usar drawPath() para obtener la forma deseada.

    Espero que esto te ponga en la dirección correcta.

Mira este ejemplo que está creando un triángulo para que puedas obtener la lógica de él 🙂

http://looksok.wordpress.com/2013/08/24/android-triangle-arrow-defined-as-an-xml-shape/

Otra solución que encontré pero no probó, así que prueba esto también

 @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); } 

Fuente: grupo de Google

Tercera solución: esta podría ser una biblioteca útil

PathDrawable es un Drawable que dibuja formas simples usando el objeto Path.

Es tarde para volver a contraer .. Pero espero que ayude a alguien …

  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; } 

Llamar a esto donde quieras usar

  Drawable drawable = getResources().getDrawable( R.drawable.placeholder ); Bitmap b=getHexagonShape(drawableToBitmap(drawable)); img=(ImageView)findViewById(R.id.imageView); img.setImageBitmap(b); 

La siguiente función lee su imagen como bitmap de entrada y devuelve un bitmap que tiene forma hexagonal

 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; } 

No sé si el OP obtuvo la respuesta que estaba buscando, pero aquí va.

He creado una vista personalizada, que extiende ImageView, que hará el trabajo un poco mejor. La respuesta aquí simplemente crea un maks dentro de ImageView y te obliga a establecer la imagen como fondo

Mi vista le permite configurar la imagen como un bitmap estándar, maneja CenterCrop y escala de la imagen. De hecho, establece la máscara afuera, y con el mismo borde más la sombra paralela.

Y, si eso no es suficiente, puede crear fácilmente formas personalizadas para renderizar, simplemente ampliando la clase RenderShape. (Se incluyen 4 formas en la biblioteca: círculo, triángulo, hexágono y octágono)

Echa un vistazo a mi github

Aclamaciones

Lo he solucionado usando este código:

  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; } 

Puedes usar la forma de Android ImageView de siamed.

https://github.com/siyamed/android-shape-imageview

  

Lea la documentación en github, hay muchas opciones disponibles.