How to make layout with rounded corners..?

后端 未结 18 2909
独厮守ぢ
独厮守ぢ 2020-11-22 09:37

How can I make a layout with rounded corners? I want to apply rounded corners to my LinearLayout.

相关标签:
18条回答
  • 2020-11-22 10:11
    <?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, just put padding same value as stroke, so border can be visible, regardeless image size

    0 讨论(0)
  • 2020-11-22 10:13

    The best and simplest method would be to make use of card_background drawable in your layout. This also follows Google's material design guidelines. Just include this in you LinearLayout:

    android:background="@drawable/card_background"
    

    Add this to your drawable directory and name it 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>
    
    0 讨论(0)
  • 2020-11-22 10:14

    1: Define layout_bg.xml in 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: Add layout_bg.xml as background to your layout

    android:background="@drawable/layout_bg"
    
    0 讨论(0)
  • 2020-11-22 10:14

    With the Material Components Library you can use the MaterialShapeDrawable to draw custom shapes.

    Just put the LinearLayout in your xml layout:

    <LinearLayout
        android:id="@+id/linear_rounded"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ..>
    
        <!-- content ..... -->
    
    </LinearLayout>
    

    Then in your code you can apply a ShapeAppearanceModel. Something like:

    float radius = getResources().getDimension(R.dimen.default_corner_radius);
    
    LinearLayout linearLayout= findViewById(R.id.linear_rounded);
    ShapeAppearanceModel shapeAppearanceModel = new ShapeAppearanceModel()
        .toBuilder()
        .setAllCorners(CornerFamily.ROUNDED,radius)
        .build();
    
    MaterialShapeDrawable shapeDrawable = new MaterialShapeDrawable(shapeAppearanceModel);
    //Fill the LinearLayout with your color
    shapeDrawable.setFillColor(ContextCompat.getColorStateList(this,R.color.secondaryLightColor));
    
    
    ViewCompat.setBackground(linearLayout,shapeDrawable);
    

    Note:: it requires the version 1.1.0 of the material components library.

    0 讨论(0)
  • 2020-11-22 10:18

    I think a better way to do it is to merge 2 things:

    1. make a bitmap of the layout, as shown here.

    2. make a rounded drawable from the bitmap, as shown here

    3. set the drawable on an imageView.

    This will handle cases that other solutions have failed to solve, such as having content that has corners.

    I think it's also a bit more GPU-friendly, as it shows a single layer instead of 2 .

    The only better way is to make a totally customized view, but that's a lot of code and might take a lot of time. I think that what I suggested here is the best of both worlds.

    Here's a snippet of how it can be done:

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

    EDIT: found a nice alternative, based on "RoundKornersLayouts" library. Have a class that will be used for all of the layout classes you wish to extend, to be rounded:

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

    Then, in each of your customized layout classes, add code similar to this one:

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

    If you wish to support attributes, use this as written on the library:

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

    Another alternative, which might be easier for most uses: use MaterialCardView . It allows customizing the rounded corners, stroke color and width, and elevation.

    Example:

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

    And the result:

    Do note that there is a slight artifacts issue at the edges of the stroke (leaves some pixels of the content there), if you use it. You can notice it if you zoom in. I've reported about this issue here.

    EDIT: seems to be fixed, but not on the IDE. Reported here.

    0 讨论(0)
  • 2020-11-22 10:20

    Here's a copy of a XML file to create a drawable with a white background, black border and rounded corners:

     <?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>
    

    save it as a xml file in the drawable directory, Use it like you would use any drawable background(icon or resource file) using its resource name (R.drawable.your_xml_name)

    0 讨论(0)
提交回复
热议问题