Как сделать макет с закругленными углами ..?

392

Как я могу сделать макет с закругленными углами? Я хочу применить закругленные углы к моему LinearLayout.

  • 0
    создать фигуру с углом, а затем установить в качестве фона .. в чем проблема?
  • 0
    вам просто нужно установить округлое изображение в качестве фона макета, иначе сделайте форму, как сказано в первом комментарии
Показать ещё 2 комментария
Теги:
image
layout

17 ответов

800
Лучший ответ

1: Определите layout_bg.xml в drawables:

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#FFFFFF"/>
    <stroke android:width="3dp" android:color="#B1BCBE" />
    <corners android:radius="10dp"/>
    <padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
</shape>

2: Добавить layout_bg.xml в качестве фона для вашего макета

android:background="@drawable/layout_bg"
  • 154
    Это не работает как вы установили, это фон, поэтому контент переопределяет закругленные углы, и если у вас есть контент, который рисует по углам, вы не увидите, что они закруглены.
  • 11
    Почти всегда мой контент никогда не покрывает углы. Это работает отлично.
Показать ещё 10 комментариев
70

Для API 21+ используйте "Просмотр клипов"

Обрезание обрезанного обводки было добавлено в класс View в API 21. См. этот учебный документ или это reference для получения дополнительной информации.

Эта встроенная функция делает закругленные углы очень простыми в реализации. Он работает с любым видом или макетом и поддерживает правильное обрезание.

Здесь Что делать:

  • Создайте закругленную фигуру и установите ее в качестве фонового изображения: android:background="@drawable/round_outline"
  • Согласно документации, все, что вам нужно сделать, это следующее: android:clipToOutline="true"

К сожалению, кажется, что ошибка, и этот атрибут XML в настоящее время не распознается. К счастью, мы можем установить обрезку в Java:

  • В вашей деятельности или фрагменте: View.setClipToOutline(true)

Что это выглядит:

Изображение 3112

Специальное примечание о ImageViews

setClipToOutline() работает только тогда, когда фон "Вид" установлен в форму, пригодную для рисования. Если эта фоновая форма существует, View рассматривает контур фона как границы для целей отсечения и теневого копирования.

Это означает, что если вы хотите обогнуть углы ImageView с setClipToOutline(), ваше изображение должно начинаться с android:src вместо android:background (поскольку фон используется для закругленной формы). Если вы ДОЛЖНЫ использовать фон для установки изображения вместо src, вы можете использовать обходные пути вложенных представлений:

  • Создайте внешний макет с его фоном, настроенным на вашу форму.
  • Оберните этот макет вокруг вашего ImageView (без прокладки)
  • ImageView (включая все остальное в макете) теперь будет привязан к закругленной форме внешнего макета.
  • 7
    Не работает на API менее 21. Не могу дождаться, пока я смогу поддерживать только API 21.
  • 5
    идеально подходит для API 21+, спасибо!
Показать ещё 7 комментариев
50

Вот копия XML файла для создания рисунка с белым фоном, черной рамкой и закругленными углами:

 <?xml version="1.0" encoding="UTF-8"?> 
    <shape xmlns:android="http://schemas.android.com/apk/res/android"> 
        <solid android:color="#ffffffff"/>    

        <stroke android:width="3dp"
                android:color="#ff000000"
                />

        <padding android:left="1dp"
                 android:top="1dp"
                 android:right="1dp"
                 android:bottom="1dp"
                 /> 

        <corners android:bottomRightRadius="7dp" android:bottomLeftRadius="7dp" 
         android:topLeftRadius="7dp" android:topRightRadius="7dp"/> 
    </shape>

сохраните его как xml файл в каталоге с возможностью рисования, Используйте его, как если бы вы использовали любой выталкиваемый фон (значок или файл ресурсов), используя его имя ресурса (R.drawable.your_xml_name)

  • 4
    Понравилась возможность округления определенных углов
  • 0
    Этот ответ в значительной степени ответ, как указано выше. Единственное реальное изменение здесь - это определение каждого радиуса угла, и учитывая его одинаковое значение для каждого угла, я бы написал его в одну строку: <corners android:radius="7dp" /> :)
Показать ещё 1 комментарий
25

Я сделал так:

Проверьте скриншот:

Изображение 3218

Создать Drawable файл с именем, custom_rectangle.xml в вытяжке папке:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="@android:color/white" />

    <corners android:radius="10dip" />

    <stroke
        android:width="1dp"
        android:color="@android:color/white" />

</shape>

Теперь примените фон Rectangle на View:

mView.setBackground(R.drawlable.custom_rectangle);

Готово

  • 14
    Это не работает как вы установили, это фон, поэтому контент переопределяет закругленные углы, и если у вас есть контент, который рисует по углам, вы не увидите, что они закруглены.
21

Используйте CardView в библиотеке поддержки android v7. Хотя он немного тяжелый, он решает все проблемы и достаточно прост. Не похоже на заданный метод рисования фона, он может успешно скреплять субвью.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    card_view:cardBackgroundColor="@android:color/transparent"
    card_view:cardCornerRadius="5dp"
    card_view:cardElevation="0dp"
    card_view:contentPadding="0dp">
    <YOUR_LINEARLAYOUT_HERE>
</android.support.v7.widget.CardView>
  • 0
    Гораздо лучше для всех, кто может «позволить» это, чем что-либо еще. Меня сбивает с толку, что такая базовая вещь не является частью стандартных представлений Android, а является основным в CSS практически для любого веб-браузера.
21

Я думаю, что лучший способ сделать это - объединить 2 вещи:

  1. сделайте растровое изображение макета, как показано здесь.

  2. сделать округлый рисунок из растрового изображения, как показано здесь

  3. установить рисование на imageView.

Это будет обрабатывать случаи, которые другие решения не смогли решить, например, наличие контента, который имеет углы.

Я думаю, что он также немного более дружественен к GPU, так как показывает один слой вместо 2.

Единственный лучший способ - создать полностью настраиваемое представление, но это много кода и может занять много времени. Я думаю, что то, что я предложил здесь, является лучшим из обоих миров.

Вот фрагмент того, как это можно сделать:

RoundedCornersDrawable.java

/**
 * shows a bitmap as if it had rounded corners. based on :
 * http://rahulswackyworld.blogspot.co.il/2013/04/android-drawables-with-rounded_7.html
 * easy alternative from support library: RoundedBitmapDrawableFactory.create( ...) ; 
 */
public class RoundedCornersDrawable extends BitmapDrawable {

    private final BitmapShader bitmapShader;
    private final Paint p;
    private final RectF rect;
    private final float borderRadius;

    public RoundedCornersDrawable(final Resources resources, final Bitmap bitmap, final float borderRadius) {
        super(resources, bitmap);
        bitmapShader = new BitmapShader(getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        final Bitmap b = getBitmap();
        p = getPaint();
        p.setAntiAlias(true);
        p.setShader(bitmapShader);
        final int w = b.getWidth(), h = b.getHeight();
        rect = new RectF(0, 0, w, h);
        this.borderRadius = borderRadius < 0 ? 0.15f * Math.min(w, h) : borderRadius;
    }

    @Override
    public void draw(final Canvas canvas) {
        canvas.drawRoundRect(rect, borderRadius, borderRadius, p);
    }
}

CustomView.java

public class CustomView extends ImageView {
    private View mMainContainer;
    private boolean mIsDirty=false;

    // TODO for each change of views/content, set mIsDirty to true and call invalidate

    @Override
    protected void onDraw(final Canvas canvas) {
        if (mIsDirty) {
            mIsDirty = false;
            drawContent();
            return;
        }
        super.onDraw(canvas);
    }

    /**
     * draws the view content to a bitmap. code based on :
     * http://nadavfima.com/android-snippet-inflate-a-layout-draw-to-a-bitmap/
     */
    public static Bitmap drawToBitmap(final View viewToDrawFrom, final int width, final int height) {
        // Create a new bitmap and a new canvas using that bitmap
        final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        final Canvas canvas = new Canvas(bmp);
        viewToDrawFrom.setDrawingCacheEnabled(true);
        // Supply measurements
        viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(canvas.getWidth(), MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(canvas.getHeight(), MeasureSpec.EXACTLY));
        // Apply the measures so the layout would resize before drawing.
        viewToDrawFrom.layout(0, 0, viewToDrawFrom.getMeasuredWidth(), viewToDrawFrom.getMeasuredHeight());
        // and now the bmp object will actually contain the requested layout
        canvas.drawBitmap(viewToDrawFrom.getDrawingCache(), 0, 0, new Paint());
        return bmp;
    }

    private void drawContent() {
        if (getMeasuredWidth() <= 0 || getMeasuredHeight() <= 0)
            return;
        final Bitmap bitmap = drawToBitmap(mMainContainer, getMeasuredWidth(), getMeasuredHeight());
        final RoundedCornersDrawable drawable = new RoundedCornersDrawable(getResources(), bitmap, 15);
        setImageDrawable(drawable);
    }

}

РЕДАКТИРОВАТЬ: нашел хорошую альтернативу, основанную на библиотеке "RoundKornersLayouts". У вас должен быть класс, который будет использоваться для всех классов макетов, которые вы хотите расширить:

//based on https://github.com/JcMinarro/RoundKornerLayouts
class CanvasRounder(cornerRadius: Float, cornerStrokeColor: Int = 0, cornerStrokeWidth: Float = 0F) {
    private val path = android.graphics.Path()
    private lateinit var rectF: RectF
    private var strokePaint: Paint?
    var cornerRadius: Float = cornerRadius
        set(value) {
            field = value
            resetPath()
        }

    init {
        if (cornerStrokeWidth <= 0)
            strokePaint = null
        else {
            strokePaint = Paint()
            strokePaint!!.style = Paint.Style.STROKE
            strokePaint!!.isAntiAlias = true
            strokePaint!!.color = cornerStrokeColor
            strokePaint!!.strokeWidth = cornerStrokeWidth
        }
    }

    fun round(canvas: Canvas, drawFunction: (Canvas) -> Unit) {
        val save = canvas.save()
        canvas.clipPath(path)
        drawFunction(canvas)
        if (strokePaint != null)
            canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, strokePaint)
        canvas.restoreToCount(save)
    }

    fun updateSize(currentWidth: Int, currentHeight: Int) {
        rectF = android.graphics.RectF(0f, 0f, currentWidth.toFloat(), currentHeight.toFloat())
        resetPath()
    }

    private fun resetPath() {
        path.reset()
        path.addRoundRect(rectF, cornerRadius, cornerRadius, Path.Direction.CW)
        path.close()
    }

}

Затем в каждом из ваших настроенных классов макета добавьте код, подобный этому:

class RoundedConstraintLayout : ConstraintLayout {
    private lateinit var canvasRounder: CanvasRounder

    constructor(context: Context) : super(context) {
        init(context, null, 0)
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        init(context, attrs, 0)
    }

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
        init(context, attrs, defStyle)
    }

    private fun init(context: Context, attrs: AttributeSet?, defStyle: Int) {
        val array = context.obtainStyledAttributes(attrs, R.styleable.RoundedCornersView, 0, 0)
        val cornerRadius = array.getDimension(R.styleable.RoundedCornersView_corner_radius, 0f)
        val cornerStrokeColor = array.getColor(R.styleable.RoundedCornersView_corner_stroke_color, 0)
        val cornerStrokeWidth = array.getDimension(R.styleable.RoundedCornersView_corner_stroke_width, 0f)
        array.recycle()
        canvasRounder = CanvasRounder(cornerRadius,cornerStrokeColor,cornerStrokeWidth)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
            setLayerType(FrameLayout.LAYER_TYPE_SOFTWARE, null)
        }
    }

    override fun onSizeChanged(currentWidth: Int, currentHeight: Int, oldWidth: Int, oldheight: Int) {
        super.onSizeChanged(currentWidth, currentHeight, oldWidth, oldheight)
        canvasRounder.updateSize(currentWidth, currentHeight)
    }

    override fun draw(canvas: Canvas) = canvasRounder.round(canvas) { super.draw(canvas) }

    override fun dispatchDraw(canvas: Canvas) = canvasRounder.round(canvas) { super.dispatchDraw(canvas) }

}

Если вы хотите поддерживать атрибуты, используйте это так, как написано в библиотеке:

<resources>
  <declare-styleable name="RoundedCornersView">
      <attr name="corner_radius" format="dimension"/>
      <attr name="corner_stroke_width" format="dimension"/>
      <attr name="corner_stroke_color" format="color"/>
  </declare-styleable>
</resources>

Другая альтернатива, которая может быть проще для большинства применений: используйте MaterialCardView. Это позволяет настраивать закругленные углы, цвет и ширину обводки, а также высоту.

Пример:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:clipChildren="false" android:clipToPadding="false"
    tools:context=".MainActivity">

    <com.google.android.material.card.MaterialCardView
        android:layout_width="100dp" android:layout_height="100dp" android:layout_gravity="center"
        app:cardCornerRadius="8dp" app:cardElevation="8dp" app:strokeColor="#f00" app:strokeWidth="2dp">

        <ImageView
            android:layout_width="match_parent" android:layout_height="match_parent" android:background="#0f0"/>

    </com.google.android.material.card.MaterialCardView>

</FrameLayout>

И результат:

Изображение 3219

Обратите внимание, что по краям обводки возникает небольшая проблема с артефактами (при этом остаются некоторые пиксели содержимого), если вы ее используете. Вы можете заметить это, если вы увеличите масштаб. Я сообщил об этой проблеме здесь.

  • 0
    Спасибо за сборку этого удивительного ответа, это заставило меня двигаться в правильном направлении, но я мог бы помочь с очень связанной проблемой здесь stackoverflow.com/questions/25877515/…
  • 0
    Это приводит к ошибке, поскольку в ImageView нет доступного конструктора по умолчанию.
Показать ещё 8 комментариев
10

Попробуйте это...

1.create drawable xml (custom_layout.xml):

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >

<solid android:color="#FFFFFF" />

<stroke
    android:width="2dp"
    android:color="#FF785C" />

<corners android:radius="10dp" />

</shape>

2.add ваш фон представления

android:background="@drawable/custom_layout"
  • 0
    Как я уже писал выше о подобном решении: это не работает. как вы установили, это фон, поэтому контент переопределяет закругленные углы, и если у вас есть контент, который рисует по углам, вы не увидите, что они закруглены.
5

Лучший способ сделать это:

background_activity.xml

<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:gravity="fill">
        <color android:color="@color/black"/>
    </item>
    <item>
        <shape android:gravity="fill">
            <solid android:color="@color/white"/>
            <corners android:radius="10dip"/>
            <padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" />
        </shape>
    </item>
</layer-list>

Это также будет работать ниже API 21 и даст вам примерно следующее:

Изображение 3220


Если вы хотите сделать больше усилий более эффективным, используйте android.support.v7.widget.CardView с его атрибутом cardCornerRadius (и установите атрибут elevation на 0dp, чтобы избавиться от любой сопровождающей теневой тени с помощью cardView). Кроме того, это будет работать от уровня API до 15.

  • 0
    Если содержимое соответствует фону, оно переопределит его. Это на самом деле не обрезает форму, которую вы установили.
  • 0
    Вы имеете в виду другое мнение? Можете ли вы обновить код, чтобы показать, что вы имеете в виду? Идея состоит в том, что закругленные углы не поместили бы черную область. По углам должен быть прозрачный цвет.
Показать ещё 2 комментария
4

Используйте CardView, чтобы получить закругленные края для любых макетов. Используйте card_view: cardCornerRadius = "5dp" для просмотра карт с закругленными краями.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:card_view="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

      <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardCornerRadius="5dp">
          <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:padding="15dp"
                android:weightSum="1">

                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight=".3"
                    android:text="@string/quote_code"
                    android:textColor="@color/white"
                    android:textSize="@dimen/text_head_size" />

                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight=".7"
                    android:text="@string/quote_details"
                    android:textColor="@color/white"
                    android:textSize="@dimen/text_head_size" />
            </LinearLayout>
       </android.support.v7.widget.CardView>
   </LinearLayout>
  • 0
    CardView из библиотеки support.v7, вы можете использовать из API7 или выше.
3

Функция для установки радиуса угла программно

static void setCornerRadius(GradientDrawable drawable, float topLeft,
        float topRight, float bottomRight, float bottomLeft) {
    drawable.setCornerRadii(new float[] { topLeft, topLeft, topRight, topRight,
            bottomRight, bottomRight, bottomLeft, bottomLeft });
}

static void setCornerRadius(GradientDrawable drawable, float radius) {
    drawable.setCornerRadius(radius);
}

С помощью

GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.GREEN);
setCornerRadius(gradientDrawable, 20f);
//or setCornerRadius(gradientDrawable, 20f, 40f, 60f, 80f); 

view.setBackground(gradientDrawable);
3

Если вы хотите, чтобы ваш макет был округлым, лучше всего использовать CardView, он предоставляет множество функций, чтобы сделать дизайн красивым.

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    card_view:cardCornerRadius="5dp">
      <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight=".3"
                android:text="@string/quote_code"
                android:textColor="@color/white"
                android:textSize="@dimen/text_head_size" />
      </LinearLayout>
</android.support.v7.widget.CardView>

С этим card_view: cardCornerRadius = "5dp", вы можете изменить радиус.

3

Самый лучший и простой способ - использовать card_background, который можно использовать в вашем макете. Это также следует руководству Google по разработке материалов. Просто включите это в вас LinearLayout:

android:background="@drawable/card_background"

Добавьте это в свою выпадающую директорию и назовите ее card_background.xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item>
        <shape android:shape="rectangle">
            <solid android:color="#BDBDBD"/>
            <corners android:radius="5dp"/>
        </shape>
    </item>

    <item
        android:left="0dp"
        android:right="0dp"
        android:top="0dp"
        android:bottom="2dp">
        <shape android:shape="rectangle">
            <solid android:color="#ffffff"/>
            <corners android:radius="5dp"/>
        </shape>
    </item>
</layer-list>
3
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#FFFFFF"/>
    <stroke android:width="3dip" android:color="#B1BCBE" />
    <corners android:radius="10dip"/>
    <padding android:left="3dip" android:top="3dip" android:right="3dip" android:bottom="3dip" />
</shape>

@David, просто добавьте одно значение, как штрих, поэтому граница может быть видимой, безразмерный размер изображения

1

Я взял ответ @gauravsapiens с моими комментариями, чтобы дать вам разумное представление о том, на что будут влиять параметры.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Background color -->
    <solid android:color="@color/white" />

    <!-- Stroke around the background, width and color -->
    <stroke android:width="4dp" android:color="@color/drop_shadow"/>

    <!-- The corners of the shape -->
    <corners android:radius="4dp"/>

    <!-- Padding for the background, e.g the Text inside a TextView will be 
    located differently -->
    <padding android:left="10dp" android:right="10dp" 
             android:bottom="10dp" android:top="10dp" />

</shape>

Если вы просто хотите создать форму, которая закругляет углы, удалится отступ и обводка. Если вы также удалите твердое тело, вы фактически создадите закругленные углы на прозрачном фоне.

Ради того, чтобы быть ленивым, я создал форму внизу, которая представляет собой сплошной белый фон с закругленными углами - наслаждайтесь! :)

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Background color -->
    <solid android:color="@color/white" />

    <!-- The corners of the shape -->
    <corners android:radius="4dp"/>

</shape>
0

Intead of XML

android:background="@drawable/layout_shape"

использовать (в коде):

getDialog().getWindow().setBackgroundDrawableResource(R.drawable.layout_shape)
0
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="@dimen/_10sdp"
android:shape="rectangle">

<solid android:color="@color/header" />

<corners
    android:bottomLeftRadius="@dimen/_5sdp"
    android:bottomRightRadius="@dimen/_5sdp"
    android:topLeftRadius="@dimen/_5sdp"
    android:topRightRadius="@dimen/_5sdp" />

0
Create your xml in drawable, layout_background.xml

 <?xml version="1.0" encoding="utf-8"?>
        <shape xmlns:android="http://schemas.android.com/apk/res/android" >
        <solid android:color="@color/your_colour" />
        <stroke
            android:width="2dp"
            android:color="@color/your_colour" />
        <corners android:radius="10dp" />      
        </shape>
 <--width, color, radius should be as per your requirement-->

Finally in your layout.xml file write below line

 android:background="@drawable/layout_background"
  • 0
    пожалуйста исправьте ваш xml код, спасибо!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню