<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>안드로이드 개발 기록</title>
    <link>https://tolylim.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 5 Sep 2026 04:02:40 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>tolylim</managingEditor>
    <item>
      <title>MVI 정리</title>
      <link>https://tolylim.tistory.com/6</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;MVI 패턴이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단방향 데이터 흐름을 통해 상태를 관리하는 패턴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(일반적으로 단일 상태 사용!)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;704&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wEFda/btsKzImi24E/ae2FTEKgMfQ45fmo2xpMBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wEFda/btsKzImi24E/ae2FTEKgMfQ45fmo2xpMBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wEFda/btsKzImi24E/ae2FTEKgMfQ45fmo2xpMBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwEFda%2FbtsKzImi24E%2Fae2FTEKgMfQ45fmo2xpMBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;657&quot; height=&quot;704&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;704&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Model : 상태 담당&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- View : 사용자 이벤트를 Intent로 전달, 모델에서 받은 상태를 기반으로 화면 업데이트&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- Intent : 사용자 액션이나 이벤트 정의, 사용자 이벤트를 받아 모델로 전달하여 상태 업데이트&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;단방향 동작&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 이벤트 발생 (view -&amp;gt; intent)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 모델의 상태 변경 (intent -&amp;gt; model)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 변경된 상태로 Ui 업데이트 (model -&amp;gt; view)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;어떻게 구현할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;State : 상태는 가장 최신 값으로 유지할 수 있는 StateFlow&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Event : 이벤트는  구독자가 없으면 무시할 필요가 있기 때문에 SharedFlow&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Effect : 에러, 토스트와 같은 사이드이펙트는 한번만 보여주면 되기 때문에 Channel&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⭐️ 이벤트를 처리할 때, 바로 뷰모델의 함수를 호출하는 것이 아니라 SharedFlow로 사용하는 이유는?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- 발생하는 이벤트의 구독자가 없다면 이벤트가 무시되어야함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- 여러개 뷰모델 사용할 경우에 각 이벤트 별로 뷰모델에서 처리할 동작이 다를수도 있기 때문에 BaseViewModel에서 flow로 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MVI 장점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 앱 상태 예측 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 단방향 데이터 흐름을 통해 상태 변화가 명확해져 상태 관리가 쉬움&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 상태를 필요로할 때 저장하고 다시 불러올 때 동일한 상태를 쉽게 재현할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 비동기 작업 시 성공과 실패 상태를 구분하여 상태를 명확하게 관리할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MVI 단점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 상태 기반 Ui를 위해 초기에 Intent, State 등 정의할 코드가 많음 -&amp;gt; 라이브러리로 해결 가능 ex) orbit, mavericks&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 상태는 불변 객체이기 때문에 상태가 변할 때 마다 객체가 새로 생성되기 때문에 메모리 사용량이 증가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;-&amp;gt; 자주 변경되는 스크롤 위치 같은건 State에 포함시키기보다는 Ui 요소 내에서 관리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;-&amp;gt; 자주 변경되는 값은 별도로 관리하거나 debounce로 업데이트 주기 줄이기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MVVM과 비교&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- MVVM&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- 여러 상태를 각각 독립적으로 StateFlow 형태로 가짐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- 여러 상태가 동시에 업데이트될 때 의도하지 않은 순서로 완료될 수 있고, 일관성 유지 어려움&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- MVI :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- 단일 상태를 가짐. 여러개 값이 하나의 State로 이 객체의 최신값이 뷰에 반영됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- 모든 이벤트가 인텐트로 시작되고 State로 완료되므로, 상태는 항상 특정 인텐트의 결과로 명확함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- 여러 이벤트가 동시에 발생해도 최종 상태만 뷰에 전달&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MVI, 그래서 왜 사용하는걸까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;최근 리액트, 컴포즈 등 상태 기반 Ui 시스템이 대중화되면서 명확하고 예측 가능한 상태 관리가 중요해짐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;비동기 작업에서 데이터 흐름에 따른 상태 업데이트를 명확하게  하기 위해 사용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>tolylim</author>
      <guid isPermaLink="true">https://tolylim.tistory.com/6</guid>
      <comments>https://tolylim.tistory.com/6#entry6comment</comments>
      <pubDate>Wed, 6 Nov 2024 20:57:59 +0900</pubDate>
    </item>
    <item>
      <title>Compose - Modifier (수정자)</title>
      <link>https://tolylim.tistory.com/4</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Modifier의 역할&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Composable의 크기, 레이아웃, 동작, 모양 변경&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 클릭, 스크롤, 드래그, 확대/축소, pull to refresh 등 상호작용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⭐️ Modifier 함수는 호출하는 순서에 따라 결과가 달라질 수 있기 때문에 순서에 신경써서 호출해야한다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;⭐️&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;자주 사용하는 Modifier 정리&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;size&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기본적으로 컴포즈에서 제공하는 레이아웃은 하위요소의 크기에 맞춰짐(WrapContentSize)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- size를 이용하여 크기를 임의로 정할 수 있음&lt;/p&gt;
&lt;pre id=&quot;code_1730440917273&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;modifier = Modifier.size(width = 400.dp, height = 100.dp)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;requiredSize&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 제약조건을 무시하고 크기를 정할 때 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 상위요소 크기에 상관없이 설정 가능&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1730440954737&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; modifier = Modifier.requiredSize(150.dp)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;widthIn/heightIn&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 최소/최대 크기를 설정할 때 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;fillMax&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- fillMaxHeight(), fillMaxWidth(), fillMaxSize()로 가득 채우는 용도로 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- fillMaxWidth(fraction = 0.5f) 처럼 파라미터로 0.0f ~ 1.0f로 비율을 사용해서 정의할 수 있음&lt;/p&gt;
&lt;pre id=&quot;code_1730441101180&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;modifier = Modifier.fillMaxWidth(0.5f)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;paddingFromBaseline&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 텍스트 기준선에 padding 추가하기 위해 사용&lt;/p&gt;
&lt;pre id=&quot;code_1730441515363&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;modifier = Modifier.paddingFromBaseline(10.dp, 10.dp)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;alignByBaseline&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Row() 내부에서 다른 컴포저블 함수들의 기준선 정렬&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;Text가 있을때 서로 글꼴이 다를경우, 기준선이 맞지 않을수 있기 때문에 사용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;statusBarsPadding/navigationBarsPadding&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; - scaffold의 innerPadding처럼 상단 상태바와 네비게이션바 패딩을 제외할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;background&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 배경을 정의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- [color, shape] 파라미터를 가진 background와 [brush, shape, alpha] 파라미터를 가진 background(그라데이션)가 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;border&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 테두리를 정의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- width (너비), color(색상), shape(모양) 파라미터로 구성&lt;/p&gt;
&lt;pre id=&quot;code_1730442228616&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; modifier = Modifier
            .border(
                width = 1.dp,
                color = Color.Blue,
                shape = RectangleShape 
            )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;aspectRatio&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 컴포넌트 크기를 비율로 설정 가능&lt;/p&gt;
&lt;pre id=&quot;code_1730442986541&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;modifier = Modifier.aspectRatio(16f / 9f)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;zIndex&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 0.0f ~ 1.0f로 설정하여 같은 부모 내에 있는 자식들 끼리 레이어 순위를 정할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 숫자가 클수록 높이 위치&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;offset&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- x, y축으로 설정한 dp 값만큼 이동&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;clickable&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 클릭 효과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;graphicsLayer&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그래픽 효과 적용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- translation(이동), scale(확대/축소), rotation(회전) 설정 가능&lt;/p&gt;
&lt;pre id=&quot;code_1730443684386&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;modifier = Modifier.graphicsLayer {
    translationX = 10f
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;onGloballyPositioned&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 전역 포지션이 변경되었을 때 호출&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Composition이 완전히 끝났을 때 호출됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- LayoutCoordinates로 다양한 포지션 정보 가져올 수 있음&lt;/p&gt;
&lt;pre id=&quot;code_1730443768616&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  Modifier.onGloballyPositioned { coordinates -&amp;gt;
        coordinates.size // 사이즈
        coordinates.positionInWindow() // 윈도우에 상대적인 position
        coordinates.positionInRoot() // 컴포즈 최상위에 상대적인 position
        coordinates.providedAlignmentLines // 제공되는 정렬 라인
        coordinates.parentLayoutCoordinates // 부모에 해당하는 인스턴스
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;then&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 변경자를 서로 연결하기 위함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>안드로이드/컴포즈</category>
      <author>tolylim</author>
      <guid isPermaLink="true">https://tolylim.tistory.com/4</guid>
      <comments>https://tolylim.tistory.com/4#entry4comment</comments>
      <pubDate>Fri, 1 Nov 2024 16:52:13 +0900</pubDate>
    </item>
    <item>
      <title>[Kotlin] 확장 함수</title>
      <link>https://tolylim.tistory.com/3</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;* 확장 함수란? &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기존에 정의된 클래스에 함수를 추가하는 기능.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;직접 만든 클래스가 아닌 다른 사람이 만든 클래스에는 함수를 추가하기 어렵기 때문에 확장 함수 사용.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-26EC42F2-CD3F-44D8-853A-0DE9BDEB7D60&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;어떤 클래스의 멤버 메소드인 것처럼 호출할 수 있지만, 실제로는 그 클래스의 밖에 선언된 함수&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;* 확장 함수 생성 방법&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPeRAB/btrK0F5eqb5/wepWNvdAD0kmY9t9AVtWfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPeRAB/btrK0F5eqb5/wepWNvdAD0kmY9t9AVtWfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPeRAB/btrK0F5eqb5/wepWNvdAD0kmY9t9AVtWfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPeRAB%2FbtrK0F5eqb5%2FwepWNvdAD0kmY9t9AVtWfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;321&quot; height=&quot;81&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;152&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;* 확장 함수 예시 (String)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZJ8C3/btrK2uIYlAq/kA9TU4kGNVJ7OuqKJKRgx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZJ8C3/btrK2uIYlAq/kA9TU4kGNVJ7OuqKJKRgx1/img.png&quot; data-alt=&quot;String 확장 함수 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZJ8C3/btrK2uIYlAq/kA9TU4kGNVJ7OuqKJKRgx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZJ8C3%2FbtrK2uIYlAq%2FkA9TU4kGNVJ7OuqKJKRgx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;529&quot; height=&quot;43&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;String 확장 함수 예시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEgjcV/btrK47Tvnez/2rGNB4b1Ct9D4PB0aHTKKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEgjcV/btrK47Tvnez/2rGNB4b1Ct9D4PB0aHTKKk/img.png&quot; data-alt=&quot;String 확장 함수 사용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEgjcV/btrK47Tvnez/2rGNB4b1Ct9D4PB0aHTKKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEgjcV%2FbtrK47Tvnez%2F2rGNB4b1Ct9D4PB0aHTKKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;531&quot; height=&quot;145&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;262&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;String 확장 함수 사용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-122B5A0D-2EBA-4278-87E9-163B5906FA4B&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;-&amp;gt; String 클래스 내부를 직접 수정하지 않고, String 클래스에 lastChar라는 새로운 함수를 생성.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fff8b2; color: #000000;&quot;&gt;receiver type&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt; (수취인 타입)&lt;/b&gt; : 확장 함수를 추가할 클래스. 확장 대상이 될 클래스 ex) String&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-122B5A0D-2EBA-4278-87E9-163B5906FA4B&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fff8b2; color: #000000;&quot;&gt;receiver object&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt; (수취인 객체)&lt;/b&gt; : receiver type이 가지고 있는 인스턴스 ex) this -&amp;gt; &quot;kotlin&quot;문구&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;* 특징&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-F716A4B2-BD4D-40D0-9CA4-06ADED900EBC&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 확장함수는 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;u&gt;정적바인딩&lt;/u&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5284007D-EBDD-4B4E-9FDD-706760F8BC72&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 이미 클래스 내부에 존재하는 클래스와 이름, 매개변수 타입, 매개변수 개수가 완벽하게 같은 함수는 무시된다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-128A2A76-819D-40D8-9BC0-6F4EA4718AB7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; (이런 경우는 확장함수 호출 시 확장함수의 내용을 호출하는 것이 아닌 멤버함수의 내용이 호출된다.)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1F067437-9047-4165-AB0E-6664E6655CAD&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 확장함수는 멤버변수를 &lt;/span&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt;오버로딩 할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-BF976DB8-F2C6-40D8-BC2F-D27F2FF729CE&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; (이름은 같고 매개변수의 타입이나 개수가 다르면 확장함수와 멤버함수 구분이 가능하다.)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-185E08EC-6148-449D-9812-1D7A72C80A51&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 확장함수는 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;오버라이드 할 수 없다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 보일러 플레이트 코드를 줄일 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- 확장 함수를 정의했어도 모든 곳에서 사용할 수는 없다. (import 했을 경우 사용 가능하다.)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7C66CF77-D202-4528-899D-534856EF3D56&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;* 정적 바인딩 vs 동적 바인딩&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p id=&quot;SE-D84846B3-E819-43E1-8D01-13A008FB0EBA&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;background-color: #fff8b2; color: #000000;&quot;&gt;정적&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 바인딩 : 함수 호출 부분에 메모리 주소 값을 저장하는 작업이 &lt;/span&gt;&lt;span style=&quot;background-color: #fff8b2; color: #000000;&quot;&gt;컴파일 시간&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;에 행해진다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9A16BC72-451E-40B3-BB9E-DC49E014E015&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; = 컴파일 이후로 값이 변경되지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-299E3B1D-49CC-411F-A779-7D77C020B960&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;background-color: #fff8b2; color: #000000;&quot;&gt;동적&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 바인딩 : 함수 호출 부분에 메모리 주소 값을 저장하는 작업이 컴파일 시간에 보류되다가 &lt;/span&gt;&lt;span style=&quot;background-color: #fff8b2; color: #000000;&quot;&gt;런타임&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;에 행해진다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-011158C1-CF35-4F12-B3D8-C1C8061C06CA&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; = 실행 시점에 객체 타입에 따라 동적으로 호출될 대상 메소드를 결정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-47131171-A6C8-4C27-9D3C-1C30D84B6B88&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;* 상속 관계의 클래스에서 확장함수를 오버라이드 할 때&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div id=&quot;SE-d76950d8-b8bf-48c0-b944-0463fd46d301&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;988&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SsfBW/btrK461nIaA/HtDMLLvlKKqOaxGboZZ6KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SsfBW/btrK461nIaA/HtDMLLvlKKqOaxGboZZ6KK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SsfBW/btrK461nIaA/HtDMLLvlKKqOaxGboZZ6KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSsfBW%2FbtrK461nIaA%2FHtDMLLvlKKqOaxGboZZ6KK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;517&quot; height=&quot;788&quot; data-origin-width=&quot;988&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-C9187DC5-24D2-420F-A7C5-D1B0150AB06B&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- &lt;b&gt;일반 멤버 함수는 오버라이드 가능&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp;-&amp;gt; 런타임 시간에 함수의 메모리 주소가 결정된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp;-&amp;gt; click() 호출 시 ButtonClass 클래스의 함수가 실행된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp;-&amp;gt; ButtonClass()라는 객체를 따라간다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;= 동적 바인딩&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-E1D5AD4C-AC7D-46F4-8841-5D5147A33EE7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;- &lt;b&gt;확장 함수는 오버라이드 불가능&amp;nbsp; &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp;-&amp;gt; 컴파일 시간에 ViewClass의 메모리 주소로 결정된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp;-&amp;gt; showOff() 호출 시 ViewClass 클래스의 함수가 실행된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp;&lt;/b&gt;-&amp;gt; ViewClass라는 타입을 따라감&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp;= 정적 바인딩&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코틀린</category>
      <category>동적바인딩</category>
      <category>안드로이드</category>
      <category>정적바인딩</category>
      <category>코틀린</category>
      <category>확장함수</category>
      <author>tolylim</author>
      <guid isPermaLink="true">https://tolylim.tistory.com/3</guid>
      <comments>https://tolylim.tistory.com/3#entry3comment</comments>
      <pubDate>Wed, 31 Aug 2022 15:46:36 +0900</pubDate>
    </item>
    <item>
      <title>[안드로이드] 안으로 둥근 뷰 만들기 (Negative Corner Radius)</title>
      <link>https://tolylim.tistory.com/2</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;1078&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ol7wh/btrHTqoLK5d/4KiQkR9uLQ5xoVctIKoB51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ol7wh/btrHTqoLK5d/4KiQkR9uLQ5xoVctIKoB51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ol7wh/btrHTqoLK5d/4KiQkR9uLQ5xoVctIKoB51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOl7wh%2FbtrHTqoLK5d%2F4KiQkR9uLQ5xoVctIKoB51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;403&quot; height=&quot;420&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;1078&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드에서 테두리가 밖으로 둥근 뷰는 많이 만들어봤지만 안으로 둥근 뷰는 한번도 만들어 본 적이 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 사각형을 만든 후에 테두리에 흰색 원을 겹쳐서 만들어보았지만 그렇게 하면 뷰를 활용하기에 어려움이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(ex) 그림자 효과를 넣을 수 없음, 배경색이 단색이 아닌 이미지나 그라데이션이 들어갈 경우 티가 남&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾아보니 안드로이드에 &lt;b&gt;CornerTreament&lt;/b&gt;라는 것이 있는데 이것을 활용해서 쉽게 만들 수 있었다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.android.com/reference/com/google/android/material/shape/CornerTreatment&quot;&gt;https://developer.android.com/reference/com/google/android/material/shape/CornerTreatment&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1658381556342&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;CornerTreatment &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;CornerTreatment public class CornerTreatment extends Object java.lang.Object &amp;nbsp;&amp;nbsp;&amp;nbsp;↳ 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&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/reference/com/google/android/material/shape/CornerTreatment&quot; data-og-url=&quot;https://developer.android.com/reference/com/google/android/material/shape/CornerTreatment&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bgx5I2/hyO8ZdPdU9/McAuqaoHKtDwqifh2haA30/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676&quot;&gt;&lt;a href=&quot;https://developer.android.com/reference/com/google/android/material/shape/CornerTreatment&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/reference/com/google/android/material/shape/CornerTreatment&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bgx5I2/hyO8ZdPdU9/McAuqaoHKtDwqifh2haA30/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;CornerTreatment &amp;nbsp;|&amp;nbsp; Android Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;CornerTreatment public class CornerTreatment extends Object java.lang.Object &amp;nbsp;&amp;nbsp;&amp;nbsp;↳ 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&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.android.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;CornerTreatment의 getCornerPath를 오버라이드 해서 작업을 해준 후 View에 확장함수를 만들어서 background를 적용하듯이 사용하였다.&amp;nbsp;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CornetTreatment의 getCornerPath와 View의 확장함수는 아래 블로그를 참고하여 구현하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.stylingandroid.com/material-shape-cutting-corners/&quot;&gt;https://blog.stylingandroid.com/material-shape-cutting-corners/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1658381755756&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Material Shape: Cutting Corners&quot; data-og-description=&quot;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&amp;hellip;&quot; data-og-host=&quot;blog.stylingandroid.com&quot; data-og-source-url=&quot;https://blog.stylingandroid.com/material-shape-cutting-corners/&quot; data-og-url=&quot;https://blog.stylingandroid.com/material-shape-cutting-corners/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://blog.stylingandroid.com/material-shape-cutting-corners/&quot; data-source-url=&quot;https://blog.stylingandroid.com/material-shape-cutting-corners/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('&amp;quot;&amp;quot;');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Material Shape: Cutting Corners&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;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&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.stylingandroid.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ConcaveRoundedCornerTreatment.kt&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;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
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MainActivity.kt&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;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
                )
            )
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽에 위치한 노란색 뷰는 &lt;b&gt;setBottomLeftCornerSize/setTopLeftCornerSize와 setBottomLeftCorner, setTopLeftCorner&lt;/b&gt;를 사용하여 왼쪽 위, 왼쪽 아래가 안으로 둥글게 구현하였고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오른쪽에 위치한 초록색 뷰는 &lt;b&gt;setBottomRightCornerSize/setTopRightCornerSize와 setBottomRightCorner, setTop&lt;b&gt;Right&lt;/b&gt;Corner&lt;/b&gt;를 사용하여 오른쪽 위, 오른쪽 아래가 안으로 둥글게 구현하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 테두리를 동일한 사이즈로 설정하려면 &lt;b&gt;setAllCornerSizes&lt;/b&gt;를 사용하면 되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 테두리를 안으로 둥글게 구현하려면 &lt;b&gt;setAllCorners&lt;/b&gt;에 ConcaveRoundedCornerTreatment를 넣어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 &lt;b&gt;EdgeTreatment&lt;/b&gt;를 활용하여 모서리에 효과를 줄 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bw1esa/btrHTrVFkPU/o6boLN5xpBkDVbaF0hLoQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bw1esa/btrHTrVFkPU/o6boLN5xpBkDVbaF0hLoQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bw1esa/btrHTrVFkPU/o6boLN5xpBkDVbaF0hLoQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbw1esa%2FbtrHTrVFkPU%2Fo6boLN5xpBkDVbaF0hLoQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;397&quot; height=&quot;420&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;912&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;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
        )
    )
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>안드로이드</category>
      <author>tolylim</author>
      <guid isPermaLink="true">https://tolylim.tistory.com/2</guid>
      <comments>https://tolylim.tistory.com/2#entry2comment</comments>
      <pubDate>Thu, 21 Jul 2022 15:17:27 +0900</pubDate>
    </item>
  </channel>
</rss>