Как сделать вид с закругленными углами?
Я пытаюсь сделать вид в Android с закругленными краями. Решение, которое я нашел до сих пор, состоит в том, чтобы определить форму с закругленными углами и использовать ее в качестве фона этого вида.
Вот что я сделал, определите drawable, как указано ниже:
<padding
android:top="2dp"
android:bottom="2dp"/>
<corners android:bottomRightRadius="20dp"
android:bottomLeftRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp"/>
Теперь я использовал это как фон для моего макета, как показано ниже:
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:clipChildren="true"
android:background="@drawable/rounded_corner">
Это прекрасно работает, я вижу, что вид имеет закругленные края.
Но в моем макете есть много других дочерних представлений, например ImageView или MapView
. Когда я размещаю ImageView
внутри вышеуказанного макета, углы изображения не обрезаются/не обрезаются, вместо этого они выглядят полными.
Я видел другие обходные пути, чтобы заставить это работать как объяснил здесь.
Но есть ли способ установить закругленные углы для вида и всех его дочерние представления содержатся в этом главном представлении, которое имеет углы?
Ответы
Ответ 1
Другой подход - создать собственный класс макета, как показано ниже. Этот макет сначала выводит его содержимое на экранное растровое изображение, маскирует растровое изображение вне экрана с закругленным прямоугольником, а затем рисует внеэкранное растровое изображение на фактическом холсте.
Я попробовал и, похоже, работает (по крайней мере, для моей простой тестовой записи). Это, конечно, скажется на производительности по сравнению с обычным макетом.
package com.example;
import android.content.Context;
import android.graphics.*;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.widget.FrameLayout;
public class RoundedCornerLayout extends FrameLayout {
private final static float CORNER_RADIUS = 40.0f;
private Bitmap maskBitmap;
private Paint paint, maskPaint;
private float cornerRadius;
public RoundedCornerLayout(Context context) {
super(context);
init(context, null, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
setWillNotDraw(false);
}
@Override
public void draw(Canvas canvas) {
Bitmap offscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
Canvas offscreenCanvas = new Canvas(offscreenBitmap);
super.draw(offscreenCanvas);
if (maskBitmap == null) {
maskBitmap = createMask(canvas.getWidth(), canvas.getHeight());
}
offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, maskPaint);
canvas.drawBitmap(offscreenBitmap, 0f, 0f, paint);
}
private Bitmap createMask(int width, int height) {
Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
Canvas canvas = new Canvas(mask);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
canvas.drawRect(0, 0, width, height, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, paint);
return mask;
}
}
Используйте это как обычный макет:
<com.example.RoundedCornerLayout
android:layout_width="200dp"
android:layout_height="200dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/test"/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#ff0000"
/>
</com.example.RoundedCornerLayout>
Ответ 2
Или вы можете использовать android.support.v7.widget.CardView
так:
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="@color/white"
card_view:cardCornerRadius="4dp">
<!--YOUR CONTENT-->
</android.support.v7.widget.CardView>
Ответ 3
shape.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#f6eef1" />
<stroke
android:width="2dp"
android:color="#000000" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
<corners android:radius="5dp" />
</shape>
и внутри вашего макета
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:clipChildren="true"
android:background="@drawable/shape">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/your image"
android:background="@drawable/shape">
</LinearLayout>
Ответ 4
Если у вас возникли проблемы при добавлении сенсорных прослушивателей в макет. Используйте этот макет в качестве родительского макета.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.widget.FrameLayout;
public class RoundedCornerLayout extends FrameLayout {
private final static float CORNER_RADIUS = 6.0f;
private float cornerRadius;
public RoundedCornerLayout(Context context) {
super(context);
init(context, null, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
@Override
protected void dispatchDraw(Canvas canvas) {
int count = canvas.save();
final Path path = new Path();
path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), cornerRadius, cornerRadius, Path.Direction.CW);
canvas.clipPath(path, Region.Op.REPLACE);
canvas.clipPath(path);
super.dispatchDraw(canvas);
canvas.restoreToCount(count);
}
}
как
<?xml version="1.0" encoding="utf-8"?>
<com.example.view.RoundedCornerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/patentItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingRight="20dp">
... your child goes here
</RelativeLayout>
</com.example.view.RoundedCornerLayout>
Ответ 5
Ответ Jaap van Hengstum отлично работает, но я думаю, что это дорого, и если мы применим этот метод на кнопке, например, сенсорный эффект будет потерян, так как представление отображается как растровое изображение.
Для меня лучший метод и самый простой из них заключается в применении маски на виде, например:
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
float cornerRadius = <whatever_you_want>;
this.path = new Path();
this.path.addRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, Path.Direction.CW);
}
@Override
protected void dispatchDraw(Canvas canvas) {
if (this.path != null) {
canvas.clipPath(this.path);
}
super.dispatchDraw(canvas);
}
Ответ 6
Создайте файл XML с именем round.xml
в drawable
папки и вставить содержимое:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#FFFFFF" />
<stroke android:width=".05dp" android:color="#d2d2d2" />
<corners android:topLeftRadius="5dp" android:topRightRadius="5dp" android:bottomRightRadius="5dp" android:bottomLeftRadius="5dp"/>
</shape>
затем используйте round.xml
качестве background
для любого элемента. Тогда это даст вам закругленные углы.
Ответ 7
В Android L вы сможете просто использовать View.setClipToOutline, чтобы получить этот эффект. В предыдущих версиях не было возможности просто обрезать содержимое случайной ViewGroup определенной формы.
Вам придется подумать о чем-то, что даст вам аналогичный эффект:
-
Если вам нужны только закругленные углы в ImageView, вы можете использовать шейдер, чтобы "закрасить" изображение поверх формы, которую вы используете в качестве фона. Взгляните на эту библиотеку для примера.
-
Если вам действительно нужно, чтобы все дети были обрезаны, возможно, вы можете по-другому взглянуть на ваш макет? Один с фоном того цвета, который вы используете, с круглой "дырой" в середине? Вы могли бы на самом деле создать пользовательскую ViewGroup, которая рисует эту форму над каждым потомком, переопределяющим метод onDraw.
Ответ 8
CardView
работал у меня в API 27 в Android Studio 3.0.1. colorPrimary
ссылался в файле res/values/colors.xml
и является лишь примером. Для layout_width из 0dp
он будет растягиваться до ширины родителя. Вам нужно будет настроить ограничения и ширину/высоту в соответствии с вашими потребностями.
<android.support.v7.widget.CardView
android:id="@+id/cardView"
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:cardCornerRadius="4dp"
app:cardBackgroundColor="@color/colorPrimary">
<!-- put your content here -->
</android.support.v7.widget.CardView>
Ответ 9
Создайте XML файл в папке Drawable с помощью следующего кода. (Имя файла, который я создал, является rounded_corner.xml)
rounded_corner.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- view background color -->
<solid
android:color="#a9c5ac" >
</solid>
<!-- view border color and width -->
<stroke
android:width="3dp"
android:color="#1c1b20" >
</stroke>
<!-- If you want to add some padding -->
<padding
android:left="4dp"
android:top="4dp"
android:right="4dp"
android:bottom="4dp" >
</padding>
<!-- Here is the corner radius -->
<corners
android:radius="10dp" >
</corners>
</shape>
И оставьте это в качестве фона для вида, для которого вы хотите сохранить границу закругленного угла. Оставим это для LinearLayout
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/rounded_corner"
android:layout_centerInParent="true">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hi, This layout has rounded corner borders ..."
android:gravity="center"
android:padding="5dp"/>
</LinearLayout>
Ответ 10
следуйте этому руководству и всему обсуждению под ним -
http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/
в соответствии с этой записью, написанной Гаем Роменом, одним из ведущих разработчиков всего инструментария Android UI, можно создать контейнер (и все его детские представления) с закругленными углами, но он объяснил, что он слишком дорогой ( от выполнения задач рендеринга).
Я порекомендую вам идти в соответствии со своим постом, и если вы хотите закругленные углы, тогда используйте закругленные углы ImageView
в соответствии с этим постом. то вы можете поместить его в контейнер с любым фоном, и вы получите тот эффект, который вам нужен.
что и я тоже в конечном итоге.
Ответ 11
public class RoundedCornerLayout extends FrameLayout {
private double mCornerRadius;
public RoundedCornerLayout(Context context) {
this(context, null, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
public double getCornerRadius() {
return mCornerRadius;
}
public void setCornerRadius(double cornerRadius) {
mCornerRadius = cornerRadius;
}
@Override
public void draw(Canvas canvas) {
int count = canvas.save();
final Path path = new Path();
path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), (float) mCornerRadius, (float) mCornerRadius, Path.Direction.CW);
canvas.clipPath(path, Region.Op.REPLACE);
canvas.clipPath(path);
super.draw(canvas);
canvas.restoreToCount(count);
}
}
Ответ 12
Предлагаемая ссылка на учебное пособие предполагает, что вам нужно установить свойства layout_width и layout_height, ваших дочерних элементов - match_parent.
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent">
Ответ 13
Отличие от ответа Яапа ван Хенгстума:
- Используйте BitmapShader вместо растрового изображения маски.
- Создание растрового изображения только один раз.
public class RoundedFrameLayout extends FrameLayout {
private Bitmap mOffscreenBitmap;
private Canvas mOffscreenCanvas;
private BitmapShader mBitmapShader;
private Paint mPaint;
private RectF mRectF;
public RoundedFrameLayout(Context context) {
super(context);
init();
}
public RoundedFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundedFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setWillNotDraw(false);
}
@Override
public void draw(Canvas canvas) {
if (mOffscreenBitmap == null) {
mOffscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
mOffscreenCanvas = new Canvas(mOffscreenBitmap);
mBitmapShader = new BitmapShader(mOffscreenBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setShader(mBitmapShader);
mRectF = new RectF(0f, 0f, canvas.getWidth(), canvas.getHeight());
}
super.draw(mOffscreenCanvas);
canvas.drawRoundRect(mRectF, 8, 8, mPaint);
}
}
Ответ 14
попробуйте это свойство с помощью линейного макета, это поможет
инструменты: контекст = "youractivity"
Ответ 15
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
Bitmap roundedBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap
.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(roundedBitmap);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
final float roundPx = pixels;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return roundedBitmap;
}
Ответ 16
Используйте форму в xml с rectangle.set свойство нижнего или верхнего радиуса как хотите. Затем примените этот xml в качестве фона для ur view.... или... используйте градиенты, чтобы сделать это из кода.