Ответ 1
Способ SMART - использовать режим смешивания PorterDuff. Это действительно простой и гладкий способ создания любого причудливого затенения, смешивания, эффекта "урожая". вы можете найти много хорошего учебника о PorterDuff. здесь хороший.
Я уже видел, как создать вытачиваемый из кругового кружка, а также как добавить вокруг него контур (AKA), здесь.
Я не могу узнать, как выполнить аналогичную задачу для округления только некоторых из углов растрового изображения внутри рисованного, без создания нового растрового изображения, и по-прежнему делать это для централизованного ImageView.
Это то, что я нашел, но он создает новое растровое изображение и при использовании его в imageView с центрированием (источник здесь):
/**
* Create rounded corner bitmap from original bitmap.
*
* @param input Original bitmap.
* @param cornerRadius Corner radius in pixel.
* @param squareTL,squareTR,squareBL,squareBR where to use square corners instead of rounded ones.
*/
public static Bitmap getRoundedCornerBitmap(final Bitmap input, final float cornerRadius, final int w, final int h,
final boolean squareTL, final boolean squareTR, final boolean squareBL, final boolean squareBR) {
final Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
final Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Rect rect = new Rect(0, 0, w, h);
final RectF rectF = new RectF(rect);
// make sure that our rounded corner is scaled appropriately
Paint paint = new Paint();
paint.setXfermode(null);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint);
// draw rectangles over the corners we want to be square
if (squareTL)
canvas.drawRect(0, 0, w / 2, h / 2, paint);
if (squareTR)
canvas.drawRect(w / 2, 0, w, h / 2, paint);
if (squareBL)
canvas.drawRect(0, h / 2, w / 2, h, paint);
if (squareBR)
canvas.drawRect(w / 2, h / 2, w, h, paint);
paint.setXfermode(PORTER_DUFF_XFERMODE_SRC_IN);
canvas.drawBitmap(input, 0, 0, paint);
return output;
}
И вот что я нашел для создания округлых углов, которые можно использовать во всех углах:
public static class RoundedCornersDrawable extends Drawable {
private final float mCornerRadius;
private final RectF mRect = new RectF();
private final BitmapShader mBitmapShader;
private final Paint mPaint;
public RoundedCornersDrawable(final Bitmap bitmap, final float cornerRadius) {
mCornerRadius = cornerRadius;
mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
mPaint = new Paint();
mPaint.setAntiAlias(false);
mPaint.setShader(mBitmapShader);
mRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
}
@Override
protected void onBoundsChange(final Rect bounds) {
super.onBoundsChange(bounds);
mRect.set(0, 0, bounds.width(), bounds.height());
}
@Override
public void draw(final Canvas canvas) {
canvas.drawRoundRect(mRect, mCornerRadius, mCornerRadius, mPaint);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha(final int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(final ColorFilter cf) {
mPaint.setColorFilter(cf);
}
}
Но это решение работает только хорошо, если изображениеView отображает контент, сохраняя при этом тот же формат изображения, что и растровое изображение, и также имеет свой размер, предварительно определенный.
Как создать вырезаемый с помощью центра, который показывает растровое изображение, имеет закругленные углы для определенных углов, а также может отображать контур/ход вокруг него?
Я хочу сделать это без создания нового растрового изображения или расширения ImageView. Используйте только drawable, который имеет растровое изображение в качестве входа.
Способ SMART - использовать режим смешивания PorterDuff. Это действительно простой и гладкий способ создания любого причудливого затенения, смешивания, эффекта "урожая". вы можете найти много хорошего учебника о PorterDuff. здесь хороший.
Я всегда использую эту библиотеку для достижения того, что вы ищете. вы можете обойти любой желаемый угол, а также добавить штрих.
Вы можете использовать его или просмотреть исходные коды только для вдохновения.
ИЗМЕНИТЬ
нет необходимости использовать Image View и сделать растровое изображение или вытащить себя и показать его в Image View. Просто замените Image View на Rounded Image View, и он будет обрабатывать все для вас без дополнительной работы в коде! Вот пример:
<com.makeramen.roundedimageview.RoundedImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/imageView1"
android:scaleType="centerCrop"
app:riv_corner_radius="8dp"
app:riv_border_width="2dp"
app:riv_border_color="#333333"
app:riv_oval="false" />
В коде просто передайте ему какой-либо ресурс изображения или используйте с ним любой Image Loader.
RoundedImageView myRoundedImage=(RoundedImageView)findViewById(R.id.imageView1);
myRoundedImage.setImageResource(R.drawable.MY_DRAWABLE);
// OR
ImageLoader.getInstance().displayImage(YOUR_IMAGE_URL, myRoundedImage);
если вы хотите просто сделать определенные углы округленными, попробуйте следующее:
<com.makeramen.roundedimageview.RoundedImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/imageView1"
android:scaleType="centerCrop"
app:riv_corner_radius_top_right="8dp"
app:riv_corner_radius_bottom_right="8dp"
app:riv_border_width="2dp"
app:riv_border_color="#333333"
app:riv_oval="false" />
Ну, вы можете создать новый .xml drawable с именем my_background и вставить этот код ниже:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<solid android:color="#00000000"/>
<corners
android:bottomLeftRadius="12dp"
android:bottomRightRadius="12dp"
android:topLeftRadius="12dp"
android:topRightRadius="12dp" />
<stroke
android:width="1dp"
android:color="#000000"
/>
</shape>
Затем вы установите для своего ImageButton, ImageView фон свой новый способ рисования, например:
android:background="@drawable/my_background"
android:scaleType="centerCrop"
или программно:
myView.setBackground(R.drawable.my_background);
Надеюсь, что это поможет!
EDIT:
Чтобы программно создать аналогичную возможность, вы можете ее использовать:
GradientDrawable shape = new GradientDrawable();
shape.setShape(GradientDrawable.RECTANGLE);
shape.setCornerRadii(new float[] { 8, 8, 8, 8, 0, 0, 0, 0 });
shape.setColor(Color.TRANSPARENT);
shape.setStroke(3, Color.BLACK);
v.setBackgroundDrawable(shape);
Хорошо, здесь моя попытка. Единственная проблема заключается в том, что "int corner" означает набор флагов. Например, 0b1111
, где каждый 1
представляет угол, который нужно закруглить, а 0
- противоположное. Приказ: TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT.
пример использования сначала, отформатированный для удобочитаемости:
((ImageView) findViewById(R.id.imageView)).setImageDrawable(
new RoundedRectDrawable(
getResources(),
bitmap,
(float) .15,
0b1101,
8,
Color.YELLOW
)
);
код:
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.os.SystemClock;
/**
* Created by mliu on 4/15/16.
*/
public class RoundedRectDrawable extends BitmapDrawable {
private final BitmapShader bitmapShader;
private final Paint p;
private final RectF rect;
private final float borderRadius;
private final float outlineBorderRadius;
private final int w;
private final int h;
private final int corners;
private final int border;
private final int bordercolor;
public RoundedRectDrawable(final Resources resources, final Bitmap bitmap, float borderRadiusSeed, int corners, int borderPX, int borderColor) {
super(resources, bitmap);
bitmapShader = new BitmapShader(getBitmap(),
BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
final Bitmap b = getBitmap();
p = getPaint();
p.setAntiAlias(true);
p.setShader(bitmapShader);
w = b.getWidth();
h = b.getHeight();
rect = new RectF(0,0,w,h);
borderRadius = borderRadiusSeed * Math.min(w, h);
border = borderPX;
this.corners = corners;
this.bordercolor = borderColor;
outlineBorderRadius = borderRadiusSeed * Math.min(w+border,h+border);
}
@Override
public void draw(final Canvas canvas) {
if ((corners&0b1111)==0){
if (border>0) {
Paint border = new Paint();
border.setColor(bordercolor);
canvas.drawRect(rect, border);
}
canvas.drawRect(rect.left + border, rect.top + border, rect.width() - border, rect.height() - border, p);
} else {
if (border >0) {
Paint border = new Paint();
border.setColor(bordercolor);
canvas.drawRoundRect(rect, outlineBorderRadius, outlineBorderRadius, border);
if ((corners & 0b1000) == 0) {
//top left
canvas.drawRect(rect.left, rect.top, rect.width() / 2, rect.height() / 2, border);
}
if ((corners & 0b0100) == 0) {
//top right
canvas.drawRect(rect.width() / 2, rect.top, rect.width(), rect.height() / 2, border);
}
if ((corners & 0b0010) == 0) {
//bottom left
canvas.drawRect(rect.left, rect.height() / 2, rect.width() / 2, rect.height(), border);
}
if ((corners & 0b0001) == 0) {
//bottom right
canvas.drawRect(rect.width() / 2, rect.height() / 2, rect.width(), rect.height(), border);
}
}
canvas.drawRoundRect(new RectF(rect.left + border, rect.top + border, rect.width() - border, rect.height() - border), borderRadius, borderRadius, p);
if ((corners & 0b1000) == 0) {
//top left
canvas.drawRect(rect.left + border, rect.top + border, rect.width() / 2, rect.height() / 2, p);
}
if ((corners & 0b0100) == 0) {
//top right
canvas.drawRect(rect.width() / 2, rect.top + border, rect.width() - border, rect.height() / 2, p);
}
if ((corners & 0b0010) == 0) {
//bottom left
canvas.drawRect(rect.left + border, rect.height() / 2, rect.width() / 2, rect.height() - border, p);
}
if ((corners & 0b0001) == 0) {
//bottom right
canvas.drawRect(rect.width() / 2, rect.height() / 2, rect.width() - border, rect.height() - border, p);
}
}
}
}
Таким образом, сначала обрабатывает контур, если необходимо, а затем растровое изображение. Сначала он отмечает холст с закругленным прямоугольником, затем "квадратизирует" каждый угол, который вы не хотите крутить. Кажется крайне неэффективным и, вероятно, является, но средним временем выполнения до минимальной оптимизации (углы = 0b0000, 10 canvas.draw) берет ~ 200us на S7. И это время SUPER несовместимо на основе использования телефона. Я достиг 80% и достигает 1,5 мс.
ПРИМЕЧАНИЯ/ПРЕДУПРЕЖДЕНИЕ: Я ПЛОХО. Это не оптимально. Там, вероятно, лучше ответы уже на SO. Тема немного необычна и сложна для поиска. Я изначально не собирался публиковать это, но на момент написания этого ответа все еще не было отмечено, и библиотека OP не хотела использовать из-за проблем с их Drawable
, фактически использовать очень похожий подход, как мое страшное решение. Итак, теперь я смущен, чтобы поделиться этим. Кроме того, хотя то, что я опубликовал сегодня, было написано вчера на 95%, я знаю, что получил часть этого кода из учебника или сообщения SO, но я не могу вспомнить, кого это атрибут, потому что я не использовал его в своем проекте, Извините, кто бы вы ни были.