Background rounded corners
Shape
For general background, we can use it directlyshape
This method naturally supports setting different four cornersradius
,for example:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:andro> <solid android:color="#8358FF" /> <corners android:bottomLeftRadius="10dp" android:bottomRightRadius="20dp" android:topLeftRadius="30dp" android:topRightRadius="40dp" /> </shape>
Tips:shape
The implementation at the code layer isGradientDrawable
, you can directly build a rounded background in the code layer
Content rounded corners
In many cases, setting different rounded corners on the four sides of the background cannot satisfy us. In most cases, we need to cut rounded corners together with the content inside. Here we need to first correct an error on the Internet.
Someone posted that it can be passedMethod to achieve the difference between four corners
radius
,as follows:
outline?.setConvexPath( Path().apply { addRoundRect( 0f, 0f, (), (), floatArrayOf( topLeftRadius, topLeftRadius, topRightRadius, topRightRadius, bottomRightRadius, bottomRightRadius, bottomLeftRadius, bottomLeftRadius ), ) } )
After actual testing, writing like this is not possible. To be precise, it is not possible on most systems (it is OK on MIUI, I don’t know if it should praise its compatibility or complain about it. My test machine uses Xiaomi, which led to me discovering this problem in the final testing stage)
After pointing out the wrong method, let's see what are the correct solutions
CardView
When it comes to cutting content and rounded corners, we will naturally think of itCardView
,actuallyCardView
The rounded corners are also passedOutline
Implemented
Someone may ask,CardView
Not only the same four cornersradius
Is it? Don't worry, let's see the magical nesting method I came up with with a sudden idea
Magical nesting method
Since oneCardView
Only oneradius
, I'll use a few moreCardView
Can nesting solve the problem?
To give the simplest example, for example, the design wants the upper part to be12dp
The rounded corners, the lower half has no rounded corners, we need a helperView
, align its top with the bottom of the parent layout, and then set it to the height of the rounded corner size ormargin
, then useCardView
, make the bottom of it align this auxiliaryView
at the bottom, set a rounded corner sizepadding
, so, becauseCardView
The boundary of the parent layout is exceeded, so the rounded corners at the bottom will not be displayed, and because we set it rightpadding
,soCardView
The contents inside can also be fully displayed, which is perfect, such as the following:
< android:layout_width="match_parent" android:layout_height="wrap_content"> <Space android: android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="12dp" app:layout_constraintTop_toBottomOf="parent" /> < android:layout_width="match_parent" android:layout_height="wrap_content" app:cardBackgroundColor="@android:color/transparent" app:cardCornerRadius="12dp" app:cardElevation="0dp" app:contentPaddingBottom="12dp" app:layout_constraintBottom_toBottomOf="@+id/guideline"> <ImageView android:layout_width="match_parent" android:layout_height="300dp" android:adjustViewBounds="true" android:background="#8358FF" /> </> </>
The example above is not nested because there are no rounded corners on the other side, then if we need the upper half to be12dp
The lower part is6dp
We can operate the rounded corners like this
The technique is the same as the example above, but we nest one in the outermost layer.CardView
, and set its rounded corner to the smaller rounded corner size6dp
, put the insideCardView
The rounded corners are set to the larger rounded corner size12dp
, the specific implementation is as follows:
< xmlns:andro xmlns:app="/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" app:cardBackgroundColor="@android:color/transparent" app:cardCornerRadius="6dp" app:cardElevation="0dp" app:layout_constraintTop_toTopOf="parent"> < android:layout_width="match_parent" android:layout_height="match_parent"> <Space android: android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="12dp" app:layout_constraintTop_toBottomOf="parent" /> < android:layout_width="match_parent" android:layout_height="wrap_content" app:cardBackgroundColor="@android:color/transparent" app:cardCornerRadius="12dp" app:cardElevation="0dp" app:contentPaddingBottom="12dp" app:layout_constraintBottom_toTopOf="@+id/guideline"> <ImageView android:layout_width="match_parent" android:layout_height="300dp" android:adjustViewBounds="true" android:background="#8358FF" /> </> </> </>
In essence, it is a large rounded corner with small rounded corners. The cutting range of large rounded corners is larger, covering the cutting range of small rounded corners. From a visual perspective, different rounded corners on both sides are realized.
So what if we want to further realize the rounded corners on three sides or the rounded corners on four sides? The principle is the same as above, except that nesting and placeholding will become more complicated. Remember one principle: small rounded corners are outside and large rounded corners are inside. I will directly paste the specific implementation below, and you can take it yourself:
- Different rounded corners on three sides (6dp in the lower left, 12dp in the upper left, 24dp in the upper right)
< xmlns:andro xmlns:app="/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> <Space android: android:layout_width="6dp" android:layout_height="match_parent" app:layout_constraintStart_toEndOf="parent" /> < android:layout_width="0dp" android:layout_height="wrap_content" app:cardBackgroundColor="@android:color/transparent" app:cardCornerRadius="6dp" app:cardElevation="0dp" app:contentPaddingRight="6dp" app:layout_constraintEnd_toEndOf="@+id/guideline" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> < android:layout_width="match_parent" android:layout_height="match_parent"> <Space android: android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="12dp" app:layout_constraintTop_toBottomOf="parent" /> < android:layout_width="match_parent" android:layout_height="wrap_content" app:cardBackgroundColor="@android:color/transparent" app:cardCornerRadius="12dp" app:cardElevation="0dp" app:contentPaddingBottom="12dp" app:layout_constraintBottom_toTopOf="@+id/guideline2"> < android:layout_width="match_parent" android:layout_height="match_parent"> <Space android: android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginEnd="24dp" app:layout_constraintEnd_toStartOf="parent" /> <Space android: android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="24dp" app:layout_constraintTop_toBottomOf="parent" /> < android:layout_width="0dp" android:layout_height="wrap_content" app:cardBackgroundColor="@android:color/transparent" app:cardCornerRadius="24dp" app:cardElevation="0dp" app:contentPaddingBottom="24dp" app:contentPaddingLeft="24dp" app:layout_constraintBottom_toBottomOf="@+id/guideline4" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@+id/guideline3"> <ImageView android:layout_width="match_parent" android:layout_height="300dp" android:adjustViewBounds="true" android:background="#8358FF" /> </> </> </> </> </> </>
- Different rounded corners on four sides (6dp lower left, 12dp upper left, 24dp upper right, 48dp lower right)
< xmlns:andro xmlns:app="/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> <Space android: android:layout_width="6dp" android:layout_height="match_parent" app:layout_constraintStart_toEndOf="parent" /> < android:layout_width="0dp" android:layout_height="wrap_content" app:cardBackgroundColor="@android:color/transparent" app:cardCornerRadius="6dp" app:cardElevation="0dp" app:contentPaddingRight="6dp" app:layout_constraintEnd_toEndOf="@+id/guideline" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> < android:layout_width="match_parent" android:layout_height="match_parent"> <Space android: android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="12dp" app:layout_constraintTop_toBottomOf="parent" /> < android:layout_width="match_parent" android:layout_height="wrap_content" app:cardBackgroundColor="@android:color/transparent" app:cardCornerRadius="12dp" app:cardElevation="0dp" app:contentPaddingBottom="12dp" app:layout_constraintBottom_toTopOf="@+id/guideline2"> < android:layout_width="match_parent" android:layout_height="match_parent"> <Space android: android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginEnd="24dp" app:layout_constraintEnd_toStartOf="parent" /> <Space android: android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="24dp" app:layout_constraintTop_toBottomOf="parent" /> < android:layout_width="0dp" android:layout_height="wrap_content" app:cardBackgroundColor="@android:color/transparent" app:cardCornerRadius="24dp" app:cardElevation="0dp" app:contentPaddingBottom="24dp" app:contentPaddingLeft="24dp" app:layout_constraintBottom_toBottomOf="@+id/guideline4" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@+id/guideline3"> < android:layout_width="match_parent" android:layout_height="match_parent"> <Space android: android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginEnd="48dp" app:layout_constraintEnd_toStartOf="parent" /> <Space android: android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginBottom="48dp" app:layout_constraintBottom_toTopOf="parent" /> < android:layout_width="0dp" android:layout_height="wrap_content" app:cardBackgroundColor="@android:color/transparent" app:cardCornerRadius="48dp" app:cardElevation="0dp" app:contentPaddingLeft="48dp" app:contentPaddingTop="48dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@+id/guideline5" app:layout_constraintTop_toTopOf="@+id/guideline6"> <ImageView android:layout_width="match_parent" android:layout_height="300dp" android:adjustViewBounds="true" android:background="#8358FF" /> </> </> </> </> </> </> </> </>
Custom ImageView
Since most of the needs of cropping content, the contents are pictures, we can also directly crop the pictures, and at this time we can customize themImageView
To cut the image into rounded corners of different sizes
clipPath
Let’s talk about the disadvantage of this method first, that is, the inability to use anti-aliasing, which is destined to be unable to be used formally, but let’s take a look at how it is implemented.
First, we need to rewriteImageView
ofonSizeChanged
Method for oursPath
Determine the route
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { (w, h, oldw, oldh) () //The radii here is our customized array of rounded corners with four sides (size is 8, clockwise from the upper left to the lower left) (0f, 0f, (), (), radii, ) }
Then we rewriteonDraw
method
override fun onDraw(canvas: Canvas) { (path) (rawBitmapCanvas) }
Some tutorials on the Internet say you want to set upPaintFlagsDrawFilter
, but in fact, it's for thisPaintFlagsDrawFilter
Set upPaint.ANTI_ALIAS_FLAG
Anti-aliasing attributes are useless, anti-aliasing is only usedPaint
Only effective can be taken if
PorterDuff
now thatclipPath
If you can't use anti-aliasing, then we can change the route curve to save the country, that is,PorterDuff
Of course, this method also has its disadvantage, that is, it cannot use hardware acceleration, but compared to the inability to use anti-aliasing, this disadvantage is nothing
First, we want to disable hardware acceleration in the constructor
init { setLayerType(LAYER_TYPE_SOFTWARE, null) }
Then rewriteonSizeChanged
Method, in this method, we need to determinePath
, construct the corresponding sizeBitmap
andCanvas
, these two are used to obtain the original rounded corners.Bitmap
of
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { (w, h, oldw, oldh) () (0f, 0f, (), (), radii, ) rawBitmap = (w, h, .ARGB_8888) rawBitmapCanvas = Canvas(rawBitmap!!) }
Then we rewriteonDraw
method
private val paint = Paint(Paint.ANTI_ALIAS_FLAG) private val xfermode = PorterDuffXfermode(.SRC_IN) override fun onDraw(canvas: Canvas) { val rawBitmap = rawBitmap ?: return val rawBitmapCanvas = rawBitmapCanvas ?: return (rawBitmapCanvas) (path, paint) = xfermode (rawBitmap, 0f, 0f, paint) = null }
Here, we call the parent classonDraw
Method to obtain the original rounded cornersBitmap
, then drawPath
, pass againPorterDuff
The overlay effect draws the original we just gotBitmap
,because.SRC_IN
The effect is to draw the intersection of two layers and display the upper layer, so we finally get a picture with rounded corners
Screenshot problem
If you want toView
Screenshot intoBitmap
,existAndroid 8.0
We can use it in the above systemsPixelCopy
, use it at this timeCardView
orOutline
There will be no problem with the cropped rounded corners, but inAndroid 8.0
In the following systems, we usually build aBitmap
ofCanvas
, and then the screenshotView
Calldraw
Method to achieve screenshot effect, and in this case, useCardView
orOutline
The cropped rounded corners will be invalid (screenshotBitmap
The rounded corners are gone), and the occurrence of this situation seems to be related to hardware acceleration. In response to this problem, my personal idea is to prepare two sets of layouts.8.0
Used aboveCardView
orOutline
, use screenshotPixelCopy
,8.0
Use the followingPorterDuff
The solution directly trims the picture to avoid performance losses to the greatest extent
Summarize
The above is what I am currently doingAndroid
Some ideas and problems encountered in implementing rounded corners of different sizes, as forCardView
I have not verified whether nesting will cause any performance problems. I have no verified any better solutions. Please point out in the comment section and let me brainstorm together.
This is the end of this article about how Android implements rounded corners of different sizes. For more related content on Android implementing rounded corners of different sizes, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!