Как сделать в Android с закругленными углами
Я пытаюсь сделать вид в 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 внутри вышеупомянутого макета, углы изображения не обрезаются/обрезаются, вместо этого он выглядит полным.
Я видел другие обходные пути, чтобы заставить его работать, как пояснил здесь.
но есть ли способ установить закругленные углы для вида и всех его дочерние представления содержатся в том главном представлении, которое округлено углы?
спасибо.
15 ответов:
другой подход заключается в создании пользовательского класса макета, как показано ниже. Этот макет сначала рисует свое содержимое в закадровом растровом изображении, маскирует закадровое растровое изображение округлым прямоугольником, а затем рисует закадровое растровое изображение на фактическом холсте.
я попробовал это, и это, кажется, работает (по крайней мере для моих простых тестах). Это, конечно, повлияет на производительность по сравнению с обычным макетом.
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>
формы.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>
или вы можете использовать
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>
Если у вас возникли проблемы при добавлении касания слушателей к макету. Используйте этот макет в качестве родительского макета.
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>
создать xml-раунд.xml в drawable folder
<solid android:color="#FFFFFF" /> <stroke android:width=".05dp" android:color="#d2d2d2" /> <corners android:topLeftRadius="5dp" android:topRightRadius="5dp" android:bottomLeftRadius="5dp" android:bottomRightRadius="5dp" />
затем использовать круглый.XML в качестве фона для элементов..Тогда это даст закругленные углы
В Android L вы сможете просто использовать вид.setClipToOutline чтобы получить этот эффект. В предыдущих версиях не было возможности просто обрезать содержимое случайной группы просмотра в определенной форме.
вам придется придумать что-то, что даст вам подобный эффект:
Если вам нужны только закругленные углы в ImageView, вы можете использовать шейдер, чтобы "нарисовать" изображение поверх формы, которую вы используете в качестве фона. Взгляните на библиотека для примера.
Если вам действительно нужно, чтобы каждый ребенок был обрезан, может быть, вы можете еще один вид на ваш макет? Один с фоном любого цвета, который вы используете, и круглое "отверстие" в середине? Вы можете фактически создать пользовательскую группу представлений, которая рисует эту фигуру над каждым дочерним элементом, переопределяющим метод onDraw.
ответ Яапа Ван Хенгстума отлично работает, однако я думаю, что это дорого, и если мы применяем этот метод на кнопку, например, сенсорный эффект теряется, так как вид отображается как растровое изображение.
для меня лучший метод и самый простой заключается в применении маски на вид, например:
@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); }
этот учебник и вся дискуссия под ним - http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/
согласно этому посту, написанному Гаем Роменом, одним из ведущих разработчиков всего инструментария Android UI, можно сделать контейнер (и все его дочерние представления) с закругленными углами, но он объяснил, что это слишком дорого (из выступлений рендеринга вопросы.)
Я буду рекомендовать вам идти в соответствии со своим постом, и если вы хотите закругленные углы, то реализовать закругленные углы
ImageView
согласно этому сообщению. затем вы можете поместить его в контейнер с любым фоном, и вы получите желаемый эффект.это то, что я сделал также и в конце концов.
ссылка на учебник, которую вы предоставили, похоже, предполагает, что вам нужно установить свойства layout_width и layout_height ваших дочерних элементов в match_parent.
<ImageView android:layout_width="match_parent" android:layout_height="match_parent">
попробуйте это свойство с вашей линейной компоновкой это поможет
инструменты:контекст=".ваша активность"
отличие от ответа Яапа Ван Хенгстума:
- использовать 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); } }
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); } }
The
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>
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; }