I'm creating a ScrollView with a FrameLayout inside. I want to design it so that only the top corners are rounded on the ScrollView. I've created a drawable shape as follows
<shape>
<solid android:color="@color/white"/>
<corners
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"
android:topLeftRadius="16dp"
android:topRightRadius="16dp"/>
<padding android:padding="0dp"/>
</shape>
I've then set the following on the ScrollView
scrollView.setOutlineProvider(ViewOutlineProvider.BACKGROUND);
scrollView.setClipToOutline(true);
When i try scrolling, the elements in my FrameLayout end up protruding through the outline of my scrollview
Excuse the drawing, but what i'm looking to achieve
However if i instead create a shape like so
<shape>
<solid android:color="@color/white"/>
<corners
android:radius="16dp"/>
<padding android:padding="0dp"/>
</shape>
It clips it just fine.
So how would i clip it if i only want the top to be cornered.
Create a layout and set its background to your shape drawable. Wrap that layout around your ImageView (with no padding) The ImageView (including anything else in the layout) will now display with rounded layout shape.
This example demonstrates how to make the corners of a button round in Android. Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main.xml. Step 3 − Add the following code to src/MainActivity.java
First of all, we need to create a drawable resource file, which has a proper definition to make TextView corners rounded, and then we have to add a background attribute to that special TextView object. Let’s do it in steps! Step 1: Create a new android studio project, and select an empty activity.
Select your mobile device as an option and then check your mobile device which will display your default screen − In the above result, it shown initial screen. Now click on button it will open custom dialog with rounded corners as shown below -
Create a Project in Android Studio with Empty Compose Activity template, and modify MainActivity.kt file as shown in the following. import androidx.compose.foundation.layout.* override fun onCreate (savedInstanceState: Bundle?) { Now, let us set the corner radius to 50 percent. Pass integer value of 50 to RoundedCornerShape ().
This is a Kotlin variation of @Jankers answer and answers to @Tony's question also. Explains how you can set only one rounded corner or two adjacent ones.
fun setCorners() {
val outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
val left = 0
val top = 0
val right = view.width
val bottom = view.height
val cornerRadiusDP = 16f
val cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, cornerRadiusDP, resources.displayMetrics).toInt()
// all corners
outline.setRoundRect(left, top, right, bottom, cornerRadius.toFloat())
/* top corners
outline.setRoundRect(left, top, right, bottom+cornerRadius, cornerRadius.toFloat())*/
/* bottom corners
outline.setRoundRect(left, top - cornerRadius, right, bottom, cornerRadius.toFloat())*/
/* left corners
outline.setRoundRect(left, top, right + cornerRadius, bottom, cornerRadius.toFloat())*/
/* right corners
outline.setRoundRect(left - cornerRadius, top, right, bottom, cornerRadius.toFloat())*/
/* top left corner
outline.setRoundRect(left , top, right+ cornerRadius, bottom + cornerRadius, cornerRadius.toFloat())*/
/* top right corner
outline.setRoundRect(left - cornerRadius , top, right, bottom + cornerRadius, cornerRadius.toFloat())*/
/* bottom left corner
outline.setRoundRect(left, top - cornerRadius, right + cornerRadius, bottom, cornerRadius.toFloat())*/
/* bottom right corner
outline.setRoundRect(left - cornerRadius, top - cornerRadius, right, bottom, cornerRadius.toFloat())*/
}
}
myView.outlineProvider = outlineProvider
myView.clipToOutline = true
}
I've managed to get this working by creating a custom ViewOutlineProvider and using that instead of a background value
ViewOutlineProvider mViewOutlineProvider = new ViewOutlineProvider() {
@Override
public void getOutline(final View view, final Outline outline) {
float cornerRadiusDP = 16f;
float cornerRadius = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, cornerRadiusDP, getResources().getDisplayMetrics());
outline.setRoundRect(0, 0, view.getWidth(), (int)(view.getHeight() + cornerRadius), cornerRadius);
}
};
scrollView.setOutlineProvider(mViewOutlineProvider);
scrollView.setClipToOutline(true);
I took the solution from @Jankers and @Dragan and condensed it, and added data binding so that it can be done from xml.
NOTE: Clipping with outline does not support corners to be different sizes!
OutlineProviders:
class RoundedCornersOutlineProvider(
val radius: Float? = null,
val topLeft: Float? = null,
val topRight: Float? = null,
val bottomLeft: Float? = null,
val bottomRight: Float? = null,
) : ViewOutlineProvider() {
private val topCorners = topLeft != null && topLeft == topRight
private val rightCorners = topRight != null && topRight == bottomRight
private val bottomCorners = bottomLeft != null && bottomLeft == bottomRight
private val leftCorners = topLeft != null && topLeft == bottomLeft
private val topLeftCorner = topLeft != null
private val topRightCorner = topRight != null
private val bottomRightCorner = bottomRight != null
private val bottomLeftCorner = bottomLeft != null
override fun getOutline(view: View, outline: Outline) {
val left = 0
val top = 0
val right = view.width
val bottom = view.height
if (radius != null) {
val cornerRadius = radius //.typedValue(resources).toFloat()
outline.setRoundRect(left, top, right, bottom, cornerRadius)
} else {
val cornerRadius = topLeft ?: topRight ?: bottomLeft ?: bottomRight ?: 0F
when {
topCorners -> outline.setRoundRect(left, top, right, bottom + cornerRadius.toInt(), cornerRadius)
bottomCorners -> outline.setRoundRect(left, top - cornerRadius.toInt(), right, bottom, cornerRadius)
leftCorners -> outline.setRoundRect(left, top, right + cornerRadius.toInt(), bottom, cornerRadius)
rightCorners -> outline.setRoundRect(left - cornerRadius.toInt(), top, right, bottom, cornerRadius)
topLeftCorner -> outline.setRoundRect(
left, top, right + cornerRadius.toInt(), bottom + cornerRadius.toInt(), cornerRadius
)
bottomLeftCorner -> outline.setRoundRect(
left, top - cornerRadius.toInt(), right + cornerRadius.toInt(), bottom, cornerRadius
)
topRightCorner -> outline.setRoundRect(
left - cornerRadius.toInt(), top, right, bottom + cornerRadius.toInt(), cornerRadius
)
bottomRightCorner -> outline.setRoundRect(
left - cornerRadius.toInt(), top - cornerRadius.toInt(), right, bottom, cornerRadius
)
}
}
}
}
class CircleOutlineProvider : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
val size = view.run { min(width, height) }
outline.setRoundRect(0, 0, size, size, (size).toFloat())
}
}
Data Binding (@BindingAdapter):
@BindingAdapter("clipCircle")
fun View.bindClipCircle(clipCircle: Boolean?) {
outlineProvider = CircleOutlineProvider()
clipToOutline = true
}
@BindingAdapter("clipRadius", "clipTopLeft", "clipTopRight", "clipBottomLeft", "clipBottomRight", requireAll = false)
fun View.bindClipCorners(radius: Float?, topLeft: Float?, topRight: Float?, bottomLeft: Float?, bottomRight: Float?) {
this.outlineProvider = RoundedCornersOutlineProvider(radius, topLeft, topRight, bottomLeft, bottomRight)
this.clipToOutline = true
}
Clipping in xml
<androidx.constraintlayout.widget.ConstraintLayout
clipCircle="@{@bool/const_true}"
...
<ImageView
clipBottomLeft="@{@dimen/green_tab_corner_radius}"
clipBottomRight="@{@dimen/green_tab_corner_radius}"
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With