
안드로이드에서 테두리가 밖으로 둥근 뷰는 많이 만들어봤지만 안으로 둥근 뷰는 한번도 만들어 본 적이 없었다.
처음에는 사각형을 만든 후에 테두리에 흰색 원을 겹쳐서 만들어보았지만 그렇게 하면 뷰를 활용하기에 어려움이 있었다.
(ex) 그림자 효과를 넣을 수 없음, 배경색이 단색이 아닌 이미지나 그라데이션이 들어갈 경우 티가 남
찾아보니 안드로이드에 CornerTreament라는 것이 있는데 이것을 활용해서 쉽게 만들 수 있었다!
https://developer.android.com/reference/com/google/android/material/shape/CornerTreatment
CornerTreatment | Android Developers
CornerTreatment public class CornerTreatment extends Object java.lang.Object ↳ com.google.android.material.shape.CornerTreatment Known direct subclasses CutCornerTreatment A corner treatment which cuts or clips the original corner of a shape with a
developer.android.com
CornerTreatment의 getCornerPath를 오버라이드 해서 작업을 해준 후 View에 확장함수를 만들어서 background를 적용하듯이 사용하였다.
CornetTreatment의 getCornerPath와 View의 확장함수는 아래 블로그를 참고하여 구현하였다.
https://blog.stylingandroid.com/material-shape-cutting-corners/
Material Shape: Cutting Corners
One of the foundations of Material Design 2.0 is the ability to define shapes to reinforce the branding being applied to our apps. At first glance what we are able to control appears to be somewhat…
blog.stylingandroid.com
ConcaveRoundedCornerTreatment.kt
class ConcaveRoundedCornerTreatment : CornerTreatment() {
override fun getCornerPath(
shapePath: ShapePath,
angle: Float,
interpolation: Float,
radius: Float
) {
val interpolatedRadius = radius * interpolation
shapePath.reset(0f, interpolatedRadius, ANGLE_LEFT, ANGLE_LEFT - angle)
shapePath.addArc(
-interpolatedRadius,
-interpolatedRadius,
interpolatedRadius,
interpolatedRadius,
ANGLE_BOTTOM,
-angle
)
}
companion object {
const val ANGLE_LEFT = 180f
const val ANGLE_BOTTOM = 90f
}
}
MainActivity.kt
package com.example.myapplication
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.TypedValue
import android.view.View
import androidx.core.content.ContextCompat
import com.example.myapplication.databinding.ActivityMainBinding
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.shape.ShapeAppearanceModel
import kotlin.math.roundToInt
private const val TYPE_LEFT = 0
private const val TYPE_RIGHT = 1
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val cornerSize = dp2px(20f, applicationContext)
binding.view1.setShapeBackground(cornerSize, R.color.yellow, TYPE_LEFT)
binding.view2.setShapeBackground(cornerSize, R.color.green, TYPE_RIGHT)
}
private fun dp2px(dp: Float, context: Context) = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, dp, context.resources.displayMetrics
)
}
private fun View.setShapeBackground(cornerSize: Float, color: Int, type: Int) {
background = if(type == TYPE_LEFT) {
MaterialShapeDrawable(
ShapeAppearanceModel.builder()
.setBottomLeftCornerSize(cornerSize)
.setTopLeftCornerSize(cornerSize)
.setTopLeftCorner(ConcaveRoundedCornerTreatment())
.setBottomLeftCorner(ConcaveRoundedCornerTreatment())
.build()
).apply {
fillColor = ColorStateList.valueOf(
ContextCompat.getColor(
context,
color
)
)
}
} else {
MaterialShapeDrawable(
ShapeAppearanceModel.builder()
.setBottomRightCornerSize(cornerSize)
.setTopRightCornerSize(cornerSize)
.setTopRightCorner(ConcaveRoundedCornerTreatment())
.setBottomRightCorner(ConcaveRoundedCornerTreatment())
.build()
).apply {
fillColor = ColorStateList.valueOf(
ContextCompat.getColor(
context,
color
)
)
}
}
}
왼쪽에 위치한 노란색 뷰는 setBottomLeftCornerSize/setTopLeftCornerSize와 setBottomLeftCorner, setTopLeftCorner를 사용하여 왼쪽 위, 왼쪽 아래가 안으로 둥글게 구현하였고,
오른쪽에 위치한 초록색 뷰는 setBottomRightCornerSize/setTopRightCornerSize와 setBottomRightCorner, setTopRightCorner를 사용하여 오른쪽 위, 오른쪽 아래가 안으로 둥글게 구현하였다.
모든 테두리를 동일한 사이즈로 설정하려면 setAllCornerSizes를 사용하면 되고
모든 테두리를 안으로 둥글게 구현하려면 setAllCorners에 ConcaveRoundedCornerTreatment를 넣어주면 된다.
추가로 EdgeTreatment를 활용하여 모서리에 효과를 줄 수도 있다.

MaterialShapeDrawable(
ShapeAppearanceModel.builder()
.setBottomLeftCornerSize(cornerSize)
.setTopLeftCornerSize(cornerSize)
.setTopLeftCorner(ConcaveRoundedCornerTreatment())
.setBottomLeftCorner(ConcaveRoundedCornerTreatment())
.setTopEdge(TriangleEdgeTreatment(cornerSize, true))
.setBottomEdge(TriangleEdgeTreatment(cornerSize, true))
.build()
).apply {
fillColor = ColorStateList.valueOf(
ContextCompat.getColor(
context,
color
)
)
}