<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hyobee_02.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 03 Jun 2025 04:46:50 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hyobee_02.log</title>
            <url>https://velog.velcdn.com/images/hyobee_02/profile/7eb625c5-1479-4798-a6d9-09698bfce235/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hyobee_02.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hyobee_02" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[📱코틀린 플로 정리]]></title>
            <link>https://velog.io/@hyobee_02/%EC%BD%94%ED%8B%80%EB%A6%B0-%ED%94%8C%EB%A1%9C-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@hyobee_02/%EC%BD%94%ED%8B%80%EB%A6%B0-%ED%94%8C%EB%A1%9C-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 03 Jun 2025 04:46:50 GMT</pubDate>
            <description><![CDATA[<h3 id="💠-코틀린-플로">💠 코틀린 플로</h3>
<h4 id="플로란">플로란?</h4>
<ul>
<li>비동기 데이터 스트림을 처리하기 위한 도구</li>
<li>시간에 따라 여러 개의 데이터를 순차적으로 처리 가능</li>
<li>LiveData처럼 UI와 연동도 가능하면서도 더 다양한 기능과 연산 제공</li>
<li>기본적으로 콜드 스트림=&gt; 구독하기 전까지는 아무 작업도 x<br>

</li>
</ul>
<h4 id="viewmodel에-flow-선언하기">ViewModel에 Flow 선언하기</h4>
<ul>
<li>ViewModel에서 Flow를 선언할 때는 보통 flow {} 블록 사용</li>
<li>블록 안에서는 emit() 함수를 이용해 데이터를 하나씩 방출</li>
</ul>
<pre><code>val numberFlow = flow {
    for (i in 1..5) {
        emit(i)
        delay(1000)
    }
}</code></pre><p>-&gt; 데이터를 하나씩, 일정한 간격으로 내보내는 구조 가능
-&gt; 비동기 루프처럼 작동
<br></p>
<h4 id="compose에서-flow-수집하기">Compose에서 Flow 수집하기</h4>
<ul>
<li>Flow를 상태로 바꿔 UI와 연결해주는 collectAsState()를 사용 </li>
<li>Flow에서 나오는 값을 실시간으로 받아 상태로 저장하고, 이 상태가 바뀌면 자동으로 UI를 다시 그려줌</li>
</ul>
<p>=&gt; 비동기 데이터를 쉽게 UI와 연결할 수 있게 해주는 도구</p>
<pre><code>val number by viewModel.numberFlow.collectAsState(initial = 0)</code></pre><br>

<h4 id="flow-중간-연산자-사용하기">Flow 중간 연산자 사용하기</h4>
<ul>
<li>Flow는 단순한 데이터 흐름만 제공하는 것이 아니라, 데이터를 가공하고 제어하는 다양한 중간 연산자 제공
ex) map은 데이터를 변환하고, filter는 조건에 맞는 데이터만 통과</li>
</ul>
<pre><code>val newFlow = numberFlow
    .filter { it % 2 == 0 }
    .map { it * 10 }</code></pre><p>=&gt; Flow는 체이닝 방식으로 데이터 흐름을 구성 가능
=&gt; 복잡한 로직도 간결하게 표현 가능
<br></p>
<h4 id="버퍼-사용하기">버퍼 사용하기</h4>
<ul>
<li>buffer()를 사용해서 생산자가 빠르더라도 데이터를 잠시 저장해두고, 소비자가 따라잡을 수 있게 함</li>
</ul>
<pre><code>numberFlow
    .buffer()
    .collect { ... }</code></pre><p>=&gt; 실제 앱에서 네트워크 속도, 사용자 입력 속도 차이 등을 처리할 때 유용
<br></p>
<h4 id="종단-연산자">종단 연산자</h4>
<ul>
<li>Flow는 마지막에 반드시 종단 연산자가 있어야 실행</li>
<li>대표적인 것:  collect()</li>
</ul>
<p>=&gt; flow로 정의만 해놓고 collect()를 하지 않으면 아무 일도x</p>
<pre><code>numberFlow.collect { value -&gt;
    Log.d(&quot;TAG&quot;, &quot;값: $value&quot;)
}</code></pre><ul>
<li>first(), toList() 같은 다양한 종단 연산자가 있으며, 상황에 따라 적절하게 사용<br>

</li>
</ul>
<h4 id="flow-평탄화">Flow 평탄화</h4>
<ul>
<li><p>이중 구조를 평탄하게 만들어주는 것 : flatMap 계열 함수</p>
</li>
<li><p>flatMapConcat: 순차적으로 연결</p>
</li>
<li><p>flatMapMerge: 병렬로 연결</p>
</li>
<li><p>flatMapLatest: 가장 마지막 것만 유지</p>
</li>
</ul>
<p>ex) 검색어 자동완성 같은 기능에서는 사용자가 입력을 바꿀 때마다 새로운 API 호출이 필요=&gt; flatMapLatest를 주로 사용
<br></p>
<h4 id="핫-플로와-콜드-플로의-차이">핫 플로와 콜드 플로의 차이</h4>
<ul>
<li>Flow는 기본적으로 콜드
=&gt; 구독자가 collect할 때마다 새롭게 실행</li>
<li>StateFlow와 SharedFlow는 핫 플로
=&gt; 한 번 방출된 데이터를 계속해서 여러 구독자에게 전달 가능</li>
<li>핫 플로는 이미 실행 중인 상태를 공유해야 할 때 사용
ex) 로그인 상태, 버튼 클릭 이벤트 등<br>

</li>
</ul>
<h4 id="콜드-flow를-핫-flow로-전환하기">콜드 Flow를 핫 Flow로 전환하기</h4>
<ul>
<li>shareIn() 또는 stateIn() 같은 연산자를 사용하면 기존의 콜드 Flow를 핫 Flow로 전환 가능
=&gt; Flow를 한 번만 실행하고 여러 구독자가 값을 공유 가능</li>
</ul>
<pre><code>val hotFlow = coldFlow.shareIn(scope, SharingStarted.Eagerly)</code></pre><p><br><br></p>
<h3 id="💠-sharedflow">💠 SharedFlow</h3>
<h4 id="sharedflow란">SharedFlow란?</h4>
<ul>
<li>일회성 이벤트를 여러 구독자에게 전달할 수 있는 핫 플로</li>
<li>토스트 메시지, 네비게이션 이동, 다이얼로그 표시처럼 UI 이벤트에 적합</li>
<li>StateFlow와는 달리 값을 기억하지 않고, emit() 하면 구독 중인 컴포넌트만 데이터를 받음<br>

</li>
</ul>
<h4 id="sharedflowdemo-프로젝트-구성">SharedFlowDemo 프로젝트 구성</h4>
<ol>
<li><p>ViewModel에 MutableSharedFlow를 선언</p>
</li>
<li><p>버튼 클릭 등으로 emit() 실행</p>
</li>
<li><p>Composable에서는 LaunchedEffect로 수집</p>
</li>
</ol>
<p>=&gt; 이벤트성 데이터를 UI와 연결할 때 직관적
<br></p>
<h4 id="compose에서-sharedflow-수집">Compose에서 SharedFlow 수집</h4>
<ul>
<li>Compose에서 SharedFlow를 수집할 땐 LaunchedEffect(Unit) 블록 사용 </li>
<li>컴포넌트가 처음 나타날 때 한 번 실행되고, 내부에서 collect()를 통해 이벤트를 감지</li>
<li>버튼 클릭 시 이벤트 발생 → Toast 표시 같은 로직이 자연스럽게 구현</li>
</ul>
<br>

<blockquote>
<ul>
<li>Flow는 순차적 데이터 흐름을 위한 코루틴 기반 도구</li>
</ul>
</blockquote>
<ul>
<li>collectAsState로 Compose와 연동 가능</li>
<li>map, filter, buffer, combine, flatMapLatest 등 다양한 연산자 제공<ul>
<li>SharedFlow는 일회성 UI 이벤트 처리에 최적</li>
<li>Compose에서는 LaunchedEffect로 SharedFlow 수집</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[📱내비게이션 & 제스처 정리]]></title>
            <link>https://velog.io/@hyobee_02/%EB%82%B4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98-%EC%A0%9C%EC%8A%A4%EC%B2%98-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@hyobee_02/%EB%82%B4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98-%EC%A0%9C%EC%8A%A4%EC%B2%98-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 27 May 2025 01:59:53 GMT</pubDate>
            <description><![CDATA[<h3 id="💠내비게이션">💠내비게이션</h3>
<h4 id="내비게이션이란">내비게이션이란?</h4>
<ul>
<li>화면 간 이동을 관리하는 것 
ex) 로그인 화면 -&gt; 홈 화면</li>
<li>Jetpack Compose에서는 기존 XML 방식과 다르게 컴포저블 함수 중심의 선언형 내비게이션 제공 <br>

</li>
</ul>
<h4 id="내비게이션-컨트롤러와-호스트">내비게이션 컨트롤러와 호스트</h4>
<pre><code>val navController = rememberNavController()

NavHost(
    navController = navController,
    startDestination = &quot;home&quot;
) {
    composable(&quot;home&quot;) { HomeScreen(navController) }
    composable(&quot;profile&quot;) { ProfileScreen() }
}
</code></pre><ul>
<li>NavController라는 내비게이션 전용 컨트롤러 선언<ul>
<li>화면 이동을 지시하는 역할을 하며, NavHost라는 구성 요소와 함께       사용</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>NavController</strong>: 화면 이동 제어
<strong>NavHost</strong>: 목적지들을 연결하고, 어느 화면에서 시작할지를 결정</p>
</blockquote>
<p>=&gt; 내비게이션 시스템은 NavController와 NavHost가 짝을 이뤄 동작!!
<br></p>
<h4 id="목적지-추가와-인수-전달">목적지 추가와 인수 전달</h4>
<ul>
<li>NavHost에 여러 개의 목적지를 등록-&gt; 각 화면을 정의 가능</li>
<li>특정 화면으로 이동할 때 필요한 정보 전달 가능 
ex) 사용자 ID를 넘겨서 프로필 페이지에서 해당 유저 정보를 불러오는 것</li>
</ul>
<p>=&gt; 목적지를 구성하고 인수를 전달함으로써 화면 간 데이터를 주고받는 내비게이션이 완성
<br></p>
<h4 id="하단-내비게이션-바-다루기">하단 내비게이션 바 다루기</h4>
<ul>
<li>앱을 보다 직관적으로 만들기 위해 하단 바를 사용</li>
<li>홈, 설정, 마이페이지 등의 화면을 아이콘으로 표시</li>
<li>Scaffold 컴포넌트와 함께 자주 사용되며, 아이템을 클릭할 때마다 NavController를 통해 해당 목적지로 이동하도록 설정</li>
</ul>
<blockquote>
<p>NavController와 BottomNavigationItem을 연결해 현재 선택된 화면을 표시하는 로직이 중요!!!</p>
</blockquote>
<p><br><br></p>
<h3 id="💠-navigationdemo-튜토리얼">💠 NavigationDemo 튜토리얼</h3>
<h4 id="프로젝트-구성">프로젝트 구성</h4>
<ul>
<li>Welcome, Home, Profile 세 개의 화면을 구현</li>
<li>각 화면은 하나의 컴포저블 함수로 만들고, 내비게이션을 통해 화면을 넘나들 수 있도록 설정<br>

</li>
</ul>
<h4 id="핵심-개념">핵심 개념</h4>
<ul>
<li>경로를 문자열로 선언</li>
<li>각 경로마다 대응되는 화면을 등록</li>
<li>버튼을 클릭하면 NavController를 통해 다른 화면으로 이동
ex) 웰컴 화면에서 홈 화면으로 이동하고, 다시 홈에서 프로필 화면으로 전환하는 흐름을 따라가는 구조</li>
</ul>
<p><br><br></p>
<h3 id="💠-하단-내비게이션-바-튜토리얼">💠 하단 내비게이션 바 튜토리얼</h3>
<h4 id="bottombardemo-프로젝트">BottomBarDemo 프로젝트</h4>
<pre><code>@Composable
fun BottomBarDemo() {
    val navController = rememberNavController()
    Scaffold(
        bottomBar = {
            BottomNavigation {
                BottomNavigationItem(
                    icon = { Icon(Icons.Default.Home, contentDescription = null) },
                    label = { Text(&quot;Home&quot;) },
                    selected = true,
                    onClick = { navController.navigate(&quot;home&quot;) }
                )
            }
        }
    ) {
        NavHost(navController, startDestination = &quot;home&quot;) {
            composable(&quot;home&quot;) { HomeScreen() }
        }
    }
}
</code></pre><ul>
<li>하단 탭 UI를 가진 앱을 구성</li>
<li>사용자는 하단 바에 있는 여러 아이콘을 눌러 각기 다른 화면으로 이동 가능</li>
<li>Scaffold 구조 내에 bottomBar 슬롯 사용 -&gt; 화면의 상단, 본문, 하단을 명확하게 분리할 수 있어 깔끔한 UI 가능<br>

</li>
</ul>
<h4 id="핵심-개념-1">핵심 개념</h4>
<ul>
<li><p>하단 바의 아이템은 리스트로 만들어 반복 출력 가능</p>
</li>
<li><p>현재 선택된 화면을 기준으로 아이템 강조 표시</p>
</li>
<li><p>아이콘 + 텍스트로 구성된 탭 UI
<br><br></p>
</li>
</ul>
<h3 id="💠-제스처-감지하기">💠 제스처 감지하기</h3>
<h4 id="클릭-제스처">클릭 제스처</h4>
<ul>
<li>가장 기본적인 제스처</li>
<li>특정 영역을 터치했을 때 반응하도록 만드는 것-&gt;  Modifier.clickable을 사용</li>
<li>클릭 시 이벤트를 처리하거나 새로운 동작 유도 가능
ex) 버튼처럼 작동하는 텍스트<br>

</li>
</ul>
<h4 id="스크롤-제스처">스크롤 제스처</h4>
<ul>
<li>화면을 위아래로 스크롤하는 동작 -&gt; Modifier.scrollable 또는 Modifier.verticalScroll 같은 모디파이어를 통해 구현 가능 </li>
<li>상태를 기억하는 ScrollState를 함께 사용하면 현재 스크롤 위치도 추적 가능</li>
</ul>
<blockquote>
<p>일반적인 UI 스크롤은 verticalScroll, 사용자 정의 스크롤은 scrollable을 사용</p>
</blockquote>
<br>

<h4 id="확대축소-회전-이동-제스처">확대/축소, 회전, 이동 제스처</h4>
<ul>
<li>이미지 뷰어나 지도를 확대/축소할 때 사용</li>
<li>Compose에서는 pointerInput과 detectTransformGestures 함수를 사용하여 처리 가능</li>
</ul>
<blockquote>
<p>zoom, rotation, pan 값을 이용해 이미지나 객체의 속성을 동적으로 변경</p>
</blockquote>
<p><br><br></p>
<h3 id="💠스와이프-제스처-감지하기">💠스와이프 제스처 감지하기</h3>
<h4 id="스와이프란">스와이프란?</h4>
<ul>
<li>좌우 혹은 상하로 손가락을 움직여 특정 동작을 유도하는 제스처
ex) 리스트에서 항목을 좌측으로 밀면 삭제 버튼이 나타나는 UI 같은 것<Br>

</li>
</ul>
<h4 id="스와이프-구현-구조">스와이프 구현 구조</h4>
<ul>
<li>swipeable 모디파이어를 통해 스와이프 기능을 구현</li>
<li>상태를 정의하고, 앵커라는 기준점을 선언하여 어느 위치까지 스와이프 되었는지 판단</li>
</ul>
<p>=&gt; 기준점의 위치와 상태값을 연결하는 앵커 맵을 잘 설계하는 것이 중요!!
<br></p>
<h4 id="swipedemo-프로젝트">SwipeDemo 프로젝트</h4>
<pre><code>val swipeState = rememberSwipeableState(0)
val anchors = mapOf(0f to 0, 300f to 1)

Box(
    modifier = Modifier
        .fillMaxWidth()
        .height(80.dp)
        .swipeable(
            state = swipeState,
            anchors = anchors,
            thresholds = { _, _ -&gt; FractionalThreshold(0.3f) },
            orientation = Orientation.Horizontal
        )
) {
    Text(&quot;스와이프 해보세요&quot;, modifier = Modifier.align(Alignment.Center))
}
</code></pre><ul>
<li>스와이프 가능한 박스 생성</li>
<li>swipeable 상태 지정</li>
<li>임계점을 설정해 어느 정도 이동해야 상태가 바뀔지를 지정
=&gt; 사용자의 스와이프 동작에 따라 UI가 자연스럽게 반응</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[📱ViewModel과 Room으로 배우는 안드로이드]]></title>
            <link>https://velog.io/@hyobee_02/ViewModel%EA%B3%BC-Room%EC%9C%BC%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C</link>
            <guid>https://velog.io/@hyobee_02/ViewModel%EA%B3%BC-Room%EC%9C%BC%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C</guid>
            <pubDate>Tue, 20 May 2025 06:32:01 GMT</pubDate>
            <description><![CDATA[<h3 id="💠안드로이드-jetpack--viewmodel">💠안드로이드 Jetpack &amp; ViewModel</h3>
<h4 id="안드로이드-jetpack">안드로이드 Jetpack</h4>
<ul>
<li>Jetpack은 안드로이드 앱 개발을 더 쉽고, 빠르고, 안정적으로 만들어주는 라이브러리 모음</li>
<li>대표 구성 요소<ul>
<li>LiveData : 생명 주기 인식 데이터 홀더</li>
<li>ViewModel : UI 상태 관리 </li>
<li>Room : SQLite를 추상화한 데이터베이스 접근 라이브러리 </li>
<li>Compose : 선언형 UI 개발 툴킷<br>

</li>
</ul>
</li>
</ul>
<h4 id="구식-아키텍처의-문제">구식 아키텍처의 문제</h4>
<ul>
<li><p>기존에는 Activity에 UI와 로직을 모두 몰아넣는 방식</p>
</li>
<li><p>화면 회전 시 데이터 손실</p>
</li>
<li><p>코드의 높은 결합도 → 유지보수 어려움</p>
</li>
<li><p>테스트 어려움</p>
<br>

</li>
</ul>
<h4 id="jetpack-기반-모던-아키텍처">Jetpack 기반 모던 아키텍처</h4>
<p>UI (Compose)
   ↓
ViewModel (UI 상태/로직)
   ↓
Repository (데이터 중개)
   ↓
Room, Network (DB/API)
<br></p>
<h4 id="viewmodel-구현">ViewModel 구현</h4>
<ul>
<li>mutableStateOf는 Compose에서 UI 상태를 자동감지</li>
</ul>
<pre><code>class DemoViewModel : ViewModel() {
    var temperature by mutableStateOf(&quot;&quot;)
}
</code></pre><br>

<h4 id="상태-기반-viewmodel">상태 기반 ViewModel</h4>
<ul>
<li>상태 변경은 UI 재구성 유도<pre><code>@Composable
fun TemperatureInput(viewModel: DemoViewModel = viewModel()) {
  TextField(
      value = viewModel.temperature,
      onValueChange = { viewModel.temperature = it }
  )
}
</code></pre></li>
</ul>
<pre><code>
&lt;br&gt;

#### ViewModel과 Activity 연결</code></pre><p>val demoViewModel: DemoViewModel by viewModels()</p>
<pre><code>
&lt;br&gt;&lt;br&gt;
### 💠ViewModel 튜토리얼
#### MainActivity에서 ViewModel 접근
- ViewModel을 통해 상태 데이터에 접근하고, UI와 연결</code></pre><p>val viewModel: DemoViewModel by viewModels()</p>
<pre><code>&lt;br&gt;

#### 온도 입력 컴포저블 구현</code></pre><p>@Composable
fun TemperatureInput(viewModel: DemoViewModel) {
    Column {
        Text(text = &quot;현재 온도: ${viewModel.temperature}&quot;)
        TextField(
            value = viewModel.temperature,
            onValueChange = { viewModel.temperature = it },
            label = { Text(&quot;온도 입력&quot;) }
        )
    }
}</p>
<pre><code>&lt;br&gt;&lt;br&gt;

### 💠안드로이드 SQLite 데이터베이스 개요
#### 데이터베이스 스키마
- 테이블의 구조 정의
- 열 이름, 타입, 제약조건 등을 포함</code></pre><p>CREATE TABLE users (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL,
  age INTEGER
);</p>
<pre><code>
&lt;br&gt;

#### 열(Column), 행(Row), 기본 키
- 열: 속성 (name, age 등)

- 행: 데이터 한 줄

- 기본 키(PK): 각 행을 고유하게 식별

&lt;br&gt;

#### SQLite의 특징
- 안드로이드 내장 경량 DB

- SQL로 데이터 조작 가능

- Room 없이 사용하려면 SQLiteOpenHelper 구현 필요
&lt;br&gt;

#### Jetpack Room
SQLite 사용을 간편하게 만들어주는 추상화 라이브러리
- @Entity: 데이터 구조 정의

- @Dao: 쿼리 정의
- @Database: DB 객체 제공

&lt;br&gt;&lt;br&gt;
### 💠RoomDemo 튜토리얼
#### RoomDemo 프로젝트 만들기
- Gradle에 Room 의존성 추가
</code></pre><p>implementation &quot;androidx.room:room-runtime:2.6.1&quot;
kapt &quot;androidx.room:room-compiler:2.6.1&quot;</p>
<pre><code>&lt;br&gt;

#### 엔티티 구축</code></pre><p>@Entity
data class Note(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val content: String
)</p>
<pre><code>&lt;br&gt;

#### DAO 구현</code></pre><p>@Dao
interface NoteDao {
    @Insert suspend fun insert(note: Note)
    @Query(&quot;SELECT * FROM Note&quot;) fun getAll(): Flow&lt;List<Note>&gt;
}</p>
<pre><code>&lt;br&gt;

#### Room DB 객체 생성</code></pre><p>@Database(entities = [Note::class], version = 1)
abstract class NoteDatabase : RoomDatabase() {
    abstract fun noteDao(): NoteDao
}</p>
<pre><code>&lt;br&gt;

#### ViewModel 추가</code></pre><p>class NoteViewModel(private val repository: NoteRepository) : ViewModel() {
    val notes = repository.allNotes.asLiveData()</p>
<pre><code>fun addNote(content: String) {
    viewModelScope.launch {
        repository.insert(Note(content = content))
    }
}</code></pre><p>}</p>
<pre><code>&lt;br&gt;


---

&gt; **ViewModel**: UI 상태 관리
**LiveData / State**: UI 재구성 트리거
**Room**: 안전하고 편리한 DB 접근
**Compose**: 선언형 UI 작성
=&gt; 이 조합은 현대 안드로이드 개발의 표준 구조


</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[📱Jetpack Compose로 배우는 애니메이션과 그래픽]]></title>
            <link>https://velog.io/@hyobee_02/Jetpack-Compose%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98%EA%B3%BC-%EA%B7%B8%EB%9E%98%ED%94%BD</link>
            <guid>https://velog.io/@hyobee_02/Jetpack-Compose%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98%EA%B3%BC-%EA%B7%B8%EB%9E%98%ED%94%BD</guid>
            <pubDate>Tue, 13 May 2025 13:06:46 GMT</pubDate>
            <description><![CDATA[<h3 id="💠시각적-애니메이션">💠시각적 애니메이션</h3>
<h4 id="animatevisibility란">AnimateVisibility란?</h4>
<ul>
<li>특정 UI 요소를 보이거나 숨길 때 자연스럽게 애니메이션 효과를 주기 위한 컴포저블</li>
<li>단순한 if 문으로 조건을 나누는 대신, 보임/숨김 상태를 자연스럽게 연결해주는 브릿지 역할</li>
<li>기본 사용법<pre><code>var isVisible by remember { mutableStateOf(true) }
</code></pre></li>
</ul>
<p>Column {
    Button(onClick = { isVisible = !isVisible }) {
        Text(&quot;토글&quot;)
    }</p>
<pre><code>AnimatedVisibility(visible = isVisible) {
    Text(&quot;보이거나 숨겨지는 텍스트입니다.&quot;)
}</code></pre><p>}</p>
<pre><code>=&gt; isVisible의 값이 바뀌면 Text의 등장과 사라짐이 애니메이션으로 처리, 단순히 View를 추가&amp;제거하는 것보다 훨씬 부드러운 UX를 만들어줌
&lt;br&gt;
#### 진입 / 이탈 애니메이션 정의
- AnimatedVisibility는 기본적으로 fade 효과가 적용되지만, 더 풍부한 애니메이션을 직접 지정 가능
- 다양한 UI 효과</code></pre><p>AnimatedVisibility(
    visible = isVisible,
    enter = fadeIn() + slideInVertically(),
    exit = fadeOut() + slideOutHorizontally()
) {
    Text(&quot;다양한 애니메이션이 적용된 텍스트&quot;)
}</p>
<pre><code>-&gt; 진입 시 위에서 슬라이드 + 페이드 인
-&gt; 이탈 시 오른쪽으로 슬라이드 + 페이드 아웃

&lt;br&gt;

####  애니메이션 스펙과 이징
- 애니메이션의 속도와 흐름 제어 가능
- ex) tween, spring, keyframes 등을 사용해 세부적인 제어 가능</code></pre><p>val slideSpec = tween(
    durationMillis = 1000,
    easing = FastOutSlowInEasing
)</p>
<pre><code>- tween: 선형 애니메이션

- spring: 탄력 있게 튀는 느낌

- keyframes: 시간마다 값을 수동 지정

- easing: 가속/감속 곡선 (UI의 자연스러움에 큰 영향)
&lt;br&gt;
#### 애니메이션 반복하기
- InfiniteTransition을 이용해 텍스트의 투명도를 반복적으로 변화시키는 예시</code></pre><p>val infiniteTransition = rememberInfiniteTransition()
val alpha by infiniteTransition.animateFloat(
    initialValue = 0f,
    targetValue = 1f,
    animationSpec = infiniteRepeatable(
        animation = tween(1000),
        repeatMode = RepeatMode.Reverse
    )
)</p>
<pre><code>=&gt; 반복 애니메이션은 로딩 애니메이션이나 호흡하는 버튼 효과 등에 유용하게 사용
&lt;br&gt;
#### 자식별로 각각 애니메이션 적용하기
- AnimatedVisibility의 내부 요소들에 각각 다른 애니메이션 부여 가능</code></pre><p>AnimatedVisibility(visible = isVisible) {
    Column {
        Text(&quot;첫 번째&quot;, modifier = Modifier.animateEnterExit(
            enter = fadeIn(), exit = fadeOut()
        ))
        Text(&quot;두 번째&quot;, modifier = Modifier.animateEnterExit(
            enter = slideInHorizontally(), exit = slideOutHorizontally()
        ))
    }
}</p>
<pre><code>=&gt; 하나의 AnimatedVisibility 안에서도 각 요소마다 다양한 효과를 넣을 수 있어서 표현력 증가
&lt;br&gt;
#### 자동으로 애니메이션 시작하기
- 컴포넌트가 자동으로 애니메이션 효과와 함께 등장하게 만들려면 LaunchedEffect 사용</code></pre><p>var isVisible by remember { mutableStateOf(false) }</p>
<p>LaunchedEffect(Unit) {
    isVisible = true
}</p>
<pre><code>=&gt; 앱 시작 시 로고, 인트로 텍스트 등을 자연스럽게 나타내는 데 활용
&lt;br&gt;
#### Crossfade – 부드러운 전환
- 서로 다른 화면이나 상태 전환을 자연스럽게 연결</code></pre><p>Crossfade(targetState = screen) { state -&gt;
    when (state) {
        &quot;Home&quot; -&gt; HomeScreen()
        &quot;Profile&quot; -&gt; ProfileScreen()
    }
}</p>
<pre><code>=&gt; 버튼 클릭 → 홈 ↔ 프로필 화면 전환 시 페이드 효과로 시선이 끊기지 않도록 도와줌
&lt;br&gt;&lt;br&gt;
### 💠상태 주도 애니메이션
#### animateFloatAsState – 회전 효과</code></pre><p>val angle by animateFloatAsState(targetValue = if (clicked) 360f else 0f)</p>
<p>Image(
    painter = painterResource(id = R.drawable.logo),
    contentDescription = null,
    modifier = Modifier.rotate(angle)
)</p>
<pre><code>=&gt; 버튼 클릭 시 이미지 회전
=&gt; rotate()에 애니메이션 상태 값을 바인딩하는 방식

&lt;br&gt;

#### animateColorAsState – 색상 변경
- 버튼 클릭으로 색상이 부드럽게 전환
</code></pre><p>val color by animateColorAsState(targetValue = if (clicked) Color.Red else Color.Blue)</p>
<p>Box(modifier = Modifier.size(100.dp).background(color))</p>
<pre><code>
&lt;br&gt;


#### animateDpAsState – 위치 이동

- 요소가 부드럽게 이동하면서 움직이는 인터랙션
</code></pre><p>val offset by animateDpAsState(
    targetValue = if (isClicked) 200.dp else 0.dp
)
Box(modifier = Modifier.offset(x = offset))</p>
<pre><code>

&lt;br&gt;

#### spring, keyframes로 정교하게 제어
- spring은 말랑말랑한 튀는 효과
- keyframes는 시간대별 크기, 위치를 수동으로 지정</code></pre><p>val scale by animateFloatAsState(
    targetValue = 1.5f,
    animationSpec = spring(dampingRatio = Spring.DampingRatioLowBouncy)
)</p>
<pre><code>
&lt;br&gt;&lt;br&gt;
### 💠Canvas 그래픽 그리기
#### Canvas란?
- 직접 2D 그래픽을 그릴 수 있는 컴포저블
- 다양한 도형, 이미지, 선 등을 수동으로 그릴 수 있어 UI를 정밀하게 조작 가능

&lt;br&gt;

#### 기본 도형 그리기
- UI에 데이터 시각화, 차트, 도형 디자인 등을 표현할 때 매우 유용
  - drawLine: 선
  - drawRect: 사각형
  - drawCircle: 원
</code></pre><p>Canvas(modifier = Modifier.size(200.dp)) {
    drawLine(Color.Black, Offset(0f, 0f), Offset(100f, 100f))
    drawRect(Color.Green, Offset(50f, 50f), Size(80f, 80f))
    drawCircle(Color.Blue, center = Offset(100f, 100f), radius = 40f)
}</p>
<pre><code>

&lt;br&gt;

#### 점선 그리기
- PathEffect.dashPathEffect()를 사용하면 선을 점선 변경 가능</code></pre><p>drawLine(
    color = Color.Red,
    start = Offset(0f, 50f),
    end = Offset(200f, 50f),
    pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f))
)</p>
<pre><code>&lt;br&gt;

#### 이미지 그리기
- 그래프나 다이어그램 위에 이미지를 오버레이 할 때</code></pre><p>val image = ImageBitmap.imageResource(id = R.drawable.sample)</p>
<p>Canvas(modifier = Modifier.size(200.dp)) {
    drawImage(image)
}</p>
<pre><code>




</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[📱코루틴과 리스트]]></title>
            <link>https://velog.io/@hyobee_02/%EC%BD%94%EB%A3%A8%ED%8B%B4%EA%B3%BC-%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@hyobee_02/%EC%BD%94%EB%A3%A8%ED%8B%B4%EA%B3%BC-%EB%A6%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Tue, 06 May 2025 09:22:23 GMT</pubDate>
            <description><![CDATA[<h3 id="💠코루틴과-launchedeffect">💠코루틴과 LaunchedEffect</h3>
<h4 id="코루틴이란">코루틴이란?</h4>
<ul>
<li>Kotlin에서 제공하는 비동기 처리를 위한 도구로, 전통적인 스레드 방식보다 훨씬 가볍고 효율적으로 동시 작업 수행 가능</li>
<li>UI 스레드를 차단하지 않고 네트워크 요청, 파일 입출력 등 시간이 오래 걸리는 작업을 수행 가능<br>

</li>
</ul>
<h4 id="주요-구성-요소">주요 구성 요소</h4>
<ul>
<li><p>CoroutineScope: 코루틴이 실행되는 범위, 생명주기 관리에 중요</p>
</li>
<li><p>일시 중단 함수: 중단 가능한 함수 -&gt; delay(), withContext() 등이 있음</p>
</li>
<li><p>디스패처 : 코루틴이 실행될 스레드를 정의 (Main, IO, Default 등)</p>
</li>
<li><p>코루틴 빌더: launch, async, withContext 등이 있으며 코루틴을 생성할 때 사용</p>
<br>

</li>
</ul>
<h4 id="compose에서-코루틴-사용하기">Compose에서 코루틴 사용하기</h4>
<ul>
<li><p>LaunchedEffect를 통해 컴포저블 안에서 코루틴 실행 가능</p>
</li>
<li><p>사용자 인터랙션에 반응하거나, 초기 데이터를 로드하는 데 자주 사용</p>
<pre><code>@Composable
fun CoroutineExample() {
  val scope = rememberCoroutineScope()

  Button(onClick = {
      scope.launch {
          delay(1000)
          println(&quot;1초 후 실행됨&quot;)
      }
  }) {
      Text(&quot;실행&quot;)
  }
}</code></pre></li>
</ul>
<p>=&gt;LaunchedEffect는 컴포저블이 처음 컴포즈될 때 특정 작업을 자동으로 실행하고 싶을 때 사용
<br></p>
<h4 id="코루틴-중지-및-재시작">코루틴 중지 및 재시작</h4>
<ul>
<li>delay()를 통해 일시 중단될 수 있으며, 재시작은 호출 컨텍스트에 의해 자동으로 처리</li>
<li>Job.cancel()을 통해 코루틴을 명시적으로 종료할 수도 있어 상황에 맞게 자원을 관리 가능<br>

</li>
</ul>
<h4 id="코루틴-채널-커뮤니케이션">코루틴 채널 커뮤니케이션</h4>
<ul>
<li>코루틴 간 데이터를 전달하기 위해 Channel이나 Flow, SharedFlow, StateFlow를 사용</li>
<li>Channel은 하나의 코루틴이 데이터를 보내고 다른 코루틴이 받을 수 있게 해주는 일종의 파이프 역할<pre><code>val channel = Channel&lt;Int&gt;()
scope.launch {
  channel.send(1)
}
scope.launch {
  val received = channel.receive()
  println(received)
}</code></pre><br><br></li>
</ul>
<h3 id="💠리스트와-그리드">💠리스트와 그리드</h3>
<blockquote>
<ul>
<li>Compose에서는 리스트나 그리드 UI를 구성할 때 성능과 메모리를 고려하여 Lazy 컴포저블을 활용</li>
</ul>
</blockquote>
<ul>
<li>Lazy 컴포저블은 보이는 항목만 렌더링하여 스크롤이 많은 UI에서도 뛰어난 성능을 제공</li>
</ul>
<h4 id="lazycolumn-기본-구조">LazyColumn 기본 구조</h4>
<ul>
<li>Jetpack Compose의 대표적인 세로 리스트로, RecyclerView의 대체<pre><code>LazyColumn {
  items(list) { item -&gt;
      Text(text = item.name)
  }
}</code></pre><br>

</li>
</ul>
<h4 id="lazyrow--lazyverticalgrid">LazyRow &amp; LazyVerticalGrid</h4>
<ul>
<li><p>LazyRow: 가로 스크롤이 가능한 리스트</p>
</li>
<li><p>LazyVerticalGrid: 격자형 레이아웃으로 상품 리스트, 갤러리 등에 적합</p>
<pre><code>LazyRow {
  items(items) { item -&gt;
      Card(Modifier.padding(8.dp)) {
          Text(item.title)
      }
  }
}</code></pre><pre><code>LazyVerticalGrid(columns = GridCells.Fixed(2)) {
  items(items) { item -&gt;
      GridItem(item)
  }
}</code></pre><br>

</li>
</ul>
<h4 id="스크롤-상태-감지">스크롤 상태 감지</h4>
<ul>
<li>rememberLazyListState()를 사용하면 스크롤 위치를 추적하고 특정 위치로 이동 가능</li>
<li>ex) 특정 버튼 클릭 시 리스트를 맨 위로 스크롤 가능<pre><code>val listState = rememberLazyListState()
LazyColumn(state = listState) { ... }
</code></pre></li>
</ul>
<p>LaunchedEffect(Unit) {
    listState.animateScrollToItem(10)
}</p>
<pre><code>&lt;br&gt;

#### 스티키 헤더 구현
- 섹션 단위로 리스트를 구분하고 현재 섹션이 상단에 고정되도록 해주는 UI 기법</code></pre><p>LazyColumn {
    stickyHeader {
        Text(&quot;헤더&quot;, modifier = Modifier.background(Color.LightGray))
    }
    items(list) {
        Text(it.title)
    }
}</p>
<pre><code>&lt;br&gt;

스크롤 위치에 반응하기
- 스크롤이 특정 위치를 넘어갔는지 여부에 따라 UI를 제어 가능</code></pre><p>val isScrolled = remember {
    derivedStateOf {
        listState.firstVisibleItemIndex &gt; 2
    }
}</p>
<pre><code>&lt;br&gt;&lt;br&gt;
### 💠Row/Column 리스트 튜토리얼
#### listdemo 프로젝트 만들기
- 새로운 Compose 프로젝트 생성
- Column 기반 리스트 구성으로 기본적인 리스트 표현 연습

#### Column 기반 리스트 만들기</code></pre><p>val items = listOf(&quot;첫 번째&quot;, &quot;두 번째&quot;, &quot;세 번째&quot;)
Column {
    items.forEach {
        Text(it, modifier = Modifier.padding(8.dp))
    }
}</p>
<pre><code>#### 수동 스크롤 리스트 만들기
- verticalScroll()을 사용하면 Lazy 없이도 스크롤 가능한 UI를 만들 수 있다.</code></pre><p>val scrollState = rememberScrollState()
Column(modifier = Modifier.verticalScroll(scrollState)) {
    for (i in 1..50) {
        Text(&quot;아이템 $i&quot;, modifier = Modifier.padding(8.dp))
    }
}</p>
<pre><code>&lt;br&gt;&lt;br&gt;

### 💠Lazy 리스트 튜토리얼
#### lazylistdemo 프로젝트 만들기
- assets/data.xml에 샘플 데이터를 추가하고 파싱

- 모델 클래스 생성: data class Item(val name: String, val imageUrl: String)
&lt;br&gt;
#### 이미지 로딩 처리하기
- Coil 라이브러리를 활용한 이미지 로딩
####  리스트 아이템 컴포저블 디자인</code></pre><p>@Composable
fun ItemCell(item: Item) {
    Row(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
        Image(...)
        Column(modifier = Modifier.padding(start = 8.dp)) {
            Text(item.name, fontWeight = FontWeight.Bold)
        }
    }
}</p>
<pre><code>#### Lazy 리스트 구현</code></pre><p>LazyColumn {
    items(items) { item -&gt;
        ItemCell(item)
    }
}</p>
<pre><code>#### 리스트 테스트 및 클릭 처리</code></pre><p>ItemCell(item = item, onClick = { navigateToDetail(item) })</p>
<pre><code>&lt;br&gt;&lt;br&gt;

### 💠스티키 헤더 &amp; 스크롤 제어
- 사용자 친화적인 리스트를 만들기 위해서는 섹션 구분, 헤더 고정, 스크롤 위치 이동 등의 기능이 필요
#### 리스트 데이터 그룹핑 &amp; 헤더 표시
- 리스트 데이터를 그룹핑하고 각 그룹에 스티키 헤더를 추가</code></pre><p>val grouped = items.groupBy { it.category }
LazyColumn {
    grouped.forEach { (category, itemList) -&gt;
        stickyHeader {
            Text(text = category, modifier = Modifier.background(Color.Gray).padding(8.dp))
        }
        items(itemList) {
            ItemCell(it)
        }
    }
}</p>
<pre><code>&lt;br&gt;

#### 스크롤 버튼 추가</code></pre><p>val scope = rememberCoroutineScope()
val listState = rememberLazyListState()</p>
<p>Button(onClick = {
    scope.launch {
        listState.animateScrollToItem(0)
    }
}) {
    Text(&quot;맨 위로&quot;)
}</p>
<pre><code></code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[📱Jetpack Compose 레이아웃 정리]]></title>
            <link>https://velog.io/@hyobee_02/Jetpack-Compose-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@hyobee_02/Jetpack-Compose-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 29 Apr 2025 16:30:22 GMT</pubDate>
            <description><![CDATA[<h3 id="💠jetpack-compose-예제-프로젝트-br">💠Jetpack Compose 예제 프로젝트 <br></h3>
<h4 id="row--column으로-레이아웃-구성">Row / Column으로 레이아웃 구성</h4>
<ul>
<li><p>기본 개념</p>
<ul>
<li>Row와 Column은 가장 기본적인 레이아웃 컴포저블</li>
<li>XML의 LinearLayout과 비슷하지만, 더 유연하고 간결한 방식으로 UI를 구성 가능</li>
</ul>
</li>
<li><p>Row 컴포저블</p>
<ul>
<li>수평 방향으로 Composable 배치</li>
</ul>
<pre><code>Row(
  modifier = Modifier
      .fillMaxWidth()
      .padding(16.dp),
  horizontalArrangement = Arrangement.SpaceBetween,
  verticalAlignment = Alignment.CenterVertically
) {
  Text(&quot;왼쪽 텍스트&quot;)
  Text(&quot;오른쪽 텍스트&quot;)
}</code></pre><ul>
<li>horizontalArrangement: 가로 방향 정렬</li>
<li>verticalAlignment: 세로 축 정렬<br></li>
</ul>
</li>
<li><p>Column 컴포저블</p>
<ul>
<li>수직 방향으로 Composable 배치<pre><code>Column(
modifier = Modifier
    .fillMaxHeight()
    .padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(&quot;위쪽 텍스트&quot;)
Button(onClick = {}) {
    Text(&quot;아래 버튼&quot;)
}
}
</code></pre></li>
</ul>
<pre><code>&lt;br&gt;
- Row와 Column 조합
 - 다단 레이아웃, 폼 구성, 프로필 페이지 등을 만들 때 주로 사용</code></pre><p>Row(modifier = Modifier.fillMaxWidth()) {
  Column(modifier = Modifier.weight(1f)) {</p>
<pre><code>  Text(&quot;이름&quot;)
  Text(&quot;이메일&quot;)</code></pre><p>  }
  Column(modifier = Modifier.weight(1f)) {</p>
<pre><code>  Text(&quot;홍길동&quot;)
  Text(&quot;honggildong@email.com&quot;)</code></pre><p>  }
}</p>
<pre><code>&lt;br&gt;

- Modifier 조합 활용
 - weight()로 유연한 공간 분배
 - padding(), background()로 시각적 커스터마이징
 - fillMaxWidth(), wrapContentSize()로 사이즈 제어
&lt;br&gt;&lt;br&gt;
</code></pre></li>
</ul>
<blockquote>
<p>Row 안에서 Column으로 나누는 구조는 form 화면 제작이나 card 뷰 구현에 자주 사용됨</p>
</blockquote>
<p><br><br></p>
<h3 id="💠box-레이아웃">💠BOX 레이아웃</h3>
<h4 id="box-컴포저블">Box 컴포저블</h4>
<ul>
<li><p>기본 개념</p>
<ul>
<li>Box는 여러 Composable을 겹쳐서 배치하는 데 사용</li>
<li>자식 요소들을 Layer처럼 쌓을 수 있어서 중첩된 UI에 강력<br>
</li>
</ul>
</li>
<li><p>Box 예제</p>
<pre><code>Box(
  modifier = Modifier
      .size(200.dp)
      .background(Color.Gray),
  contentAlignment = Alignment.Center
) {
  Icon(Icons.Default.Star, contentDescription = null)
  Text(&quot;즐겨찾기&quot;, modifier = Modifier.align(Alignment.BottomEnd))
}</code></pre><ul>
<li>contentAlignment: Box 내부의 기본 정렬 위치 지정</li>
<li>Modifier.align(): 각 자식에 개별 위치 지정 가능</li>
</ul>
</li>
<li><p>BoxScope 모디파이어</p>
<ul>
<li>align() 등으로 개별 컴포저블 정렬 제어</li>
</ul>
</li>
</ul>
<p><br><br></p>
<h3 id="💠constraintlayout">💠ConstraintLayout</h3>
<h4 id="프로젝트-필요-설정">프로젝트 필요 설정</h4>
<blockquote>
<p>implementation &quot;androidx.constraintlayout:constraintlayout-compose:1.0.1&quot;</p>
</blockquote>
<br>

<ul>
<li><p>기본 개념</p>
<ul>
<li>제약(Constraint)을 기반으로 컴포저블의 위치를 지정하는 레이아웃</li>
<li>XML ConstraintLayout과 유사하나 Compose에 맞게 설계됨</li>
<li>복잡한 관계 기반 UI 구성에 매우 유용<br>
</li>
</ul>
</li>
<li><p>사용 예시</p>
<pre><code>ConstraintLayout(modifier = Modifier.fillMaxSize()) {
  val (title, button) = createRefs()

  Text(&quot;안녕하세요&quot;, Modifier.constrainAs(title) {
      top.linkTo(parent.top, margin = 32.dp)
      start.linkTo(parent.start)
  })

  Button(onClick = {}, Modifier.constrainAs(button) {
      top.linkTo(title.bottom, margin = 16.dp)
      end.linkTo(parent.end)
  }) {
      Text(&quot;클릭&quot;)
  }
}</code></pre></li>
</ul>
<p>-&gt; createRefs()    여러 참조 객체 생성
-&gt;   createGuidelineFromTop(0.5f)    부모 기준 가이드라인 생성
-&gt;   createBottomBarrier(...)    요소들의 하단 기준점 생성</p>
<br>

<blockquote>
<p>UI가 복잡해지는 경우 Row, Column, Box만으로는 한계가 있으므로 ConstraintLayout 사용을 고려해볼 것</p>
</blockquote>
<p><br><br></p>
<h3 id="💠intrinsicsize-다루기">💠IntrinsicSize 다루기</h3>
<ul>
<li><p>기본 개념</p>
<ul>
<li>IntrinsicSize는 자식 컴포저블의 내용 크기에 따라 부모의 크기를 동적으로 결정 가능</li>
<li>주로 Divider나 비대칭 레이아웃 구성 시 유용<pre><code>Row(modifier = Modifier.height(IntrinsicSize.Min)) {
Text(&quot;짧은 텍스트&quot;, modifier = Modifier
    .padding(8.dp)
    .fillMaxHeight())
Divider(
    color = Color.Black,
    modifier = Modifier
        .width(1.dp)
        .fillMaxHeight()
)
Text(&quot;길고 긴 텍스트입니다.&quot;, modifier = Modifier
    .padding(8.dp)
    .fillMaxHeight())
}
</code></pre></li>
</ul>
<p>```</p>
</li>
<li><blockquote>
<p>텍스트 길이에 맞게 세로 구분선을 일치시킬 때 &amp; Row 안의 높이를 자식 크기에 맞추고 싶을 때 
<br><br></p>
</blockquote>
</li>
</ul>
<h3 id="💠결론">💠결론</h3>
<blockquote>
<ul>
<li>Row / Column    </li>
</ul>
</blockquote>
<ul>
<li>수평 / 수직 배치    </li>
<li>기본 폼, 리스트, 정렬된 텍스트들<ul>
<li>Box    </li>
</ul>
</li>
<li>겹치기, 자유 배치    </li>
<li>아이콘+텍스트, 배경 이미지 위 텍스트<ul>
<li>ConstraintLayout    </li>
<li>복잡한 제약 구조    </li>
<li>정밀한 레이아웃 설계, 반응형 UI</li>
<li>IntrinsicSize    </li>
<li>자식 기반 크기 설정    </li>
<li>구분선, 내부 길이 정렬 필요 시</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[📱Jetpack Compose]]></title>
            <link>https://velog.io/@hyobee_02/Jetpack-Compose</link>
            <guid>https://velog.io/@hyobee_02/Jetpack-Compose</guid>
            <pubDate>Tue, 15 Apr 2025 06:13:55 GMT</pubDate>
            <description><![CDATA[<h3 id="💠jetpack-compose-예제-프로젝트">💠Jetpack Compose 예제 프로젝트</h3>
<br>

<h4 id="컴포저블-계층구조">컴포저블 계층구조</h4>
<ul>
<li>계층구조?.<ul>
<li>Compose는 위에서 아래로 쌓는 함수형 계층 구조</li>
<li>Column, Row, Box 같은 컨테이너에 Text, Image, Button 같은 컴포저블 배치<pre><code>Column {
Text(&quot;Hello&quot;)
Row {
  Text(&quot;Compose&quot;)
  Text(&quot;World&quot;)
}
}
</code></pre></li>
</ul>
</li>
</ul>
<pre><code>=&gt; Column 안에 Text와 Row가 있고, Row 안에는 또 Text 두 개가 들어가는 구조

&lt;br&gt;

####  DemoText 컴포저블 미리보기
- Text를 출력하는 간단한 컴포저블 함수</code></pre><p>@Composable
fun DemoText() {
    Text(text = &quot;안녕하세요&quot;)
}</p>
<pre><code>- UI에서 텍스트를 보여주는 가장 기본적인 형태

- text 파라미터 외에도 style, color, fontSize 등을 설정 가능
&lt;br&gt;

#### DemoText 미리보기
- @Preview를 사용</code></pre><p>@Preview(showBackground = true)
@Composable
fun DemoTextPreview() {
    DemoText()
}</p>
<pre><code>-&gt; showBackground = true 옵션을 주면, 미리보기 배경이 흰색으로 나와서 보기 좋다!
&lt;br&gt;

#### DemoSlider 컴포저블 추가하기
-  사용자의 입력을 받을 수 있는 UI 요소</code></pre><p>@Composable
fun DemoSlider() {
    var sliderPosition by remember { mutableStateOf(0f) }</p>
<pre><code>Column {
    Text(&quot;Value: ${sliderPosition}&quot;)
    Slider(
        value = sliderPosition,
        onValueChange = { sliderPosition = it },
        valueRange = 0f..100f
    )
}</code></pre><p>}</p>
<pre><code>- remember와 mutableStateOf를 사용해 슬라이더의 값을 상태로 저장하고, 변경될 때마다 UI를 갱신
&lt;br&gt;

#### DemoScreen 컴포저블 추가하기
- 여러 개의 컴포저블을 모아 하나의 화면을 구성</code></pre><p>@Composable
fun DemoScreen() {
    Column(modifier = Modifier.padding(16.dp)) {
        DemoText()
        Spacer(modifier = Modifier.height(16.dp))
        DemoSlider()
    }
}</p>
<pre><code>- Spacer는 요소 간 간격을 줄 때 사용

- Modifier.padding으로 전체 여백도 설정 가능
&lt;br&gt;

#### DemoScreen 컴포저블 미리보기</code></pre><p>@Preview(showSystemUi = true)
@Composable
fun DemoScreenPreview() {
    DemoScreen()
}</p>
<pre><code>- showSystemUi = true를 설정하면 상태바나 네비게이션 바 등 시스템 UI도 함께 보여줘서 실제 화면 느낌
&lt;br&gt;&lt;br&gt;
### 💠Android Studio 기본 사용법
&lt;br&gt;

#### AVD
- AVD는 가상 안드로이드 기기로 실제 스마트폰 없이 앱 실행 가능

- 위치: Tools &gt; Device Manager

- 디바이스 이름, Android 버전, 화면 크기 등을 설정해 가상 디바이스 생성


&lt;br&gt; 

#### Android Emulator
- AVD를 실행하면 뜨는 창이 에뮬레이터

- 에뮬레이터에서는 실제 앱처럼 조작 가능 (클릭, 제스처, 회전, GPS 등)

- 오른쪽 바에서 다양한 설정 가능 (카메라, 배터리, 센서 등)
&lt;br&gt;

#### Android Studio 인터페이스
- 기본 화면 구성

  - Project 패널: 전체 폴더 구조

  - Editor: 코드를 작성하는 공간

  - Preview: Compose UI 미리보기

  - Logcat: 앱 실행 중 발생하는 로그 출력

&lt;br&gt;


#### 키보드 단축키
- 자동 완성 : Ctrl + Space
- 코드 포맷팅 : Ctrl + Alt + L
- 빠른 실행 : Shift + F10
- 리팩토링 메뉴 : Ctrl + Alt + Shift + T
- 심볼 검색 : Ctrl + O
- 전체 검색 : Ctrl + Shift + F
&lt;br&gt;&lt;br&gt;


### 💠Android 아키텍처 개요
&lt;br&gt;

#### MVVM 패턴
- Model - View - ViewModel 구조

- UI와 로직을 분리해서 유지보수와 테스트가 쉬워짐
- View: 화면 (Activity, Compose UI)

- ViewModel: 상태와 UI 로직

- Model: 데이터, API, DB
&lt;br&gt;


#### Jetpack 아키텍처 컴포넌트
- LiveData: 관찰 가능한 데이터

- ViewModel: 생명주기를 고려한 상태 저장

- Navigation: 화면 간 이동 처리

- Room: SQLite 기반 로컬 DB









</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[📱Android 개발을 위한 Kotlin & Jetpack Compose]]></title>
            <link>https://velog.io/@hyobee_02/Android-%EA%B0%9C%EB%B0%9C%EC%9D%84-%EC%9C%84%ED%95%9C-Kotlin-Jetpack-Compose</link>
            <guid>https://velog.io/@hyobee_02/Android-%EA%B0%9C%EB%B0%9C%EC%9D%84-%EC%9C%84%ED%95%9C-Kotlin-Jetpack-Compose</guid>
            <pubDate>Wed, 09 Apr 2025 06:03:46 GMT</pubDate>
            <description><![CDATA[<h3 id="💠kotlin이란-">💠Kotlin이란 ?</h3>
<ul>
<li><p>안드로이드 앱을 만들 때 거의 필수처럼 쓰이는 프로그래밍 언어, 2017년부터 Google이 공식 Android 개발 언어로 채택했을 만큼 중요도가 높음</p>
</li>
<li><p>특징</p>
<ul>
<li><p>간결함: 코드를 짧고 깔끔하게 쓸 수 있음</p>
</li>
<li><p>안정성: 널(null) 관련 에러 감소</p>
</li>
<li><p>현대적인 문법: 람다, 확장 함수, 데이터 클래스 등 최신 문법 지원</p>
</li>
<li><p>Java와 100% 호환 가능
<br><br></p>
</li>
</ul>
</li>
</ul>
<h4 id="변수-선언--데이터-타입">변수 선언 &amp; 데이터 타입</h4>
<ul>
<li>Kotlin에서는 변수 선언 시 val 또는 var를 사용한다.<pre><code>val name: String = &quot;홍길동&quot;  // 읽기 전용 (불변)
var age: Int = 24         // 변경 가능</code></pre></li>
</ul>
<blockquote>
<p>val : 한 번 정하면 바꿀 수 없는 값
var : 나중에 값을 바꿀 수 있는 변수</p>
</blockquote>
<blockquote>
<p>보통 변경할 필요 없는 값은 val로, 꼭 바뀌어야 하는 값만 var로!</p>
</blockquote>
<br>

<ul>
<li>Kotlin은 타입을 명시하지 않아도 자동으로 추론해줌!<pre><code>val message = &quot;안녕&quot;  // String으로 자동 추론
val count = 5         // Int로 추론</code></pre><br>

</li>
</ul>
<h4 id="널null-안정성">널(null) 안정성</h4>
<p>Kotlin의 가장 강력한 특징 중 하나는 널 안정성이다.</p>
<ul>
<li><p>널일 수도 있는 값에 접근할 땐 ?. 이나 ?:를 활용</p>
<pre><code>var nickname: String? = null  // ?를 붙이면 null 허용</code></pre><br>
</li>
<li><p>아예 null을 허용하지 않는 방식으로 안전하게 설계가능</p>
<pre><code>println(nickname?.length ?: 0)  // null이면 0 출력</code></pre><p><br><br></p>
<h3 id="💠컴포저블-함수">💠컴포저블 함수</h3>
<p>Jetpack Compose는 선언형 UI 방식을 사용하는 Android UI 툴킷으로, 이전에 말했던 것과 같이 XML 없이도 코드로 UI를 만들 수 있다.</p>
</li>
</ul>
<h4 id="컴포저블-함수란">컴포저블 함수란?</h4>
<blockquote>
<p>@Composable 어노테이션이 붙은 함수는 UI를 구성하는 블록으로,
쉽게 말해서 XML로 UI를 짜던 걸 함수로 직접 그린다고 생각하면 된다.</p>
</blockquote>
<pre><code>@Composable
fun HelloText() {
    Text(text = &quot;안녕하세요!&quot;)
}</code></pre><ul>
<li><p>이 함수는 화면에 텍스트를 보여주는 역할</p>
</li>
<li><p>Text, Button, Column 등 Compose 전용 UI 요소들은 Composable 함수 안에서만 사용 가능!
<br><br></p>
<h4 id="상태-컴포저블-vs-비상태-컴포저블">상태 컴포저블 vs 비상태 컴포저블</h4>
<p>컴포저블 함수는 <strong>상태(State)</strong>를 가지는지 여부에 따라 나눌 수 있다.<br>
📌 비상태 컴포저블</p>
</li>
<li><p>UI만 존재 , 내부 상태는 없음</p>
<pre><code>@Composable
fun Title() {
  Text(&quot;Compose&quot;)
}</code></pre><p>📌 상태 컴포저블</p>
</li>
<li><p>UI + 상태 보유, 값 변화에 따라 자동 재구성됨</p>
</li>
<li><p>remember와 mutableStateOf를 이용해 상태 저장</p>
</li>
<li><p>값이 바뀌면 자동으로 해당 UI만 다시 그림</p>
<pre><code>@Composable
fun ClickCounter() {
  var count by remember { mutableStateOf(0) }

  Button(onClick = { count++ }) {
      Text(&quot;Clicked $count times&quot;)
  }
}</code></pre><p><br><br></p>
<h4 id="컴포저블-함수-구문-정리">컴포저블 함수 구문 정리</h4>
</li>
<li><p>매개변수 전달 가능</p>
<pre><code>@Composable
fun Greeting(name: String) {
  Text(&quot;Hello, $name!&quot;)
}</code></pre></li>
<li><p>중첩 호출 가능</p>
<pre><code>@Composable
fun Screen() {
  Greeting(&quot;길동&quot;)
  Greeting(&quot;홍길동&quot;)
}</code></pre></li>
<li><p>UI 컴포넌트 조합 가능</p>
<pre><code>@Composable
fun MyScreen() {
 Column {
     Text(&quot;제목&quot;)
     Button(onClick = { /* 이벤트 */ }) {
         Text(&quot;클릭!&quot;)
     }
 }
}</code></pre><br>

</li>
</ul>
<h4 id="파운데이션foundation-컴포저블">파운데이션(Foundation) 컴포저블</h4>
<blockquote>
<p>파운데이션 컴포넌트는 Compose의 기본적인 UI 구성요소
주로 배치, 크기, 정렬 등 레이아웃의 뼈대를 다룰 때 사용된다.</p>
</blockquote>
<ul>
<li><strong>Text():</strong>     텍스트 출력</li>
<li><strong>Row {} :</strong>    가로로 나열</li>
<li><strong>Column {} :</strong>    세로로 나열</li>
<li><strong>Box {} :</strong>    겹치기, 자유 배치</li>
<li><strong>Spacer() :</strong>    빈 공간 삽입</li>
<li><strong>Image() :</strong>    이미지 출력<pre><code>@Composable
fun SimpleLayout() {
  Column(
      horizontalAlignment = Alignment.CenterHorizontally
  ) {
      Text(&quot;안녕하세요&quot;)
      Spacer(modifier = Modifier.height(10.dp))
      Text(&quot;반갑습니다&quot;)
  }
}
</code></pre></li>
</ul>
<pre><code>&lt;br&gt;

#### 머티리얼(Material) 컴포저블
&gt; Material 컴포저블은 구글의 머티리얼 디자인 철학을 적용한 컴포넌트
버튼, 카드, 스낵바 등 익숙한 UI들이 여기에 포함된다.

- **Button() :**    버튼
- **Card() :**    그림자/둥근 UI 카드
- **Scaffold() :**    전체 레이아웃 틀
- **TopAppBar() :**    상단 앱 바
- **FloatingActionButton() :**    FAB 버튼
- **Snackbar() :**    하단 메시지</code></pre><p>@Composable
fun MaterialSample() {
    Scaffold(
        topBar = {
            TopAppBar(title = { Text(&quot;My App&quot;) })
        },
        floatingActionButton = {
            FloatingActionButton(onClick = {}) {
                Icon(Icons.Default.Add, contentDescription = &quot;추가&quot;)
            }
        }
    ) {
        Text(&quot;메인 화면&quot;)
    }
}</p>
<pre><code>Scaffold는 기본 레이아웃을 정리할 때 필수 요소!
앱의 상단 바, 하단 바, 플로팅 버튼 등을 간편하게 넣을 수 있다.


&gt; - @Composable 함수는 Compose의 UI 단위!
- 상태 유무에 따라 동작이 달라짐
- 파운데이션은 레이아웃, 머티리얼은 UI 컴포넌트에 초점

----

코틀린의 기초 문법부터 시작해서 컴포저블 함수와 상태 관리, 머티리얼 컴포넌트까지 전반적인 개요를 정리해보았다. 앞으로 더 심화된 개념들과 예제들을 공부하며 실제 앱 개발까지 가보도록 하겠다!


</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[📱안드로이드 XML & Compose]]></title>
            <link>https://velog.io/@hyobee_02/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-XML-Compose</link>
            <guid>https://velog.io/@hyobee_02/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-XML-Compose</guid>
            <pubDate>Tue, 01 Apr 2025 14:45:36 GMT</pubDate>
            <description><![CDATA[<p>앞으로 안드로이드 개발을 공부하면서 배운 내용들을 정리해보려고 한다. 
오늘은 안드로이드 기본 개념, Jetpack Compose, XML 에 대해 공부한 내용을 정리해보았다.</p>
<hr>
<h3 id="💠안드로이드란-">💠안드로이드란 ?</h3>
<ul>
<li><p>Google에서 만든 모바일 운영체제(OS)</p>
</li>
<li><p>Java, Kotlin으로 개발 가능</p>
</li>
<li><p>앱 실행 환경: 스마트폰, 태블릿, TV, 웨어러블 등</p>
</li>
<li><p>구성요소 : Activity, Fragment, View &amp; ViewGroup, Intent 등</p>
<br>

</li>
</ul>
<p>우선은 간단하게만 설명하고 자세한 것은 앞으로의 자세한 공부를 통해 정리해보도록 하겠다 (●&#39;◡&#39;●)</p>
<p><br><br></p>
<h3 id="💠xml">💠XML</h3>
<p>XML은 안드로이드에서 UI를 정의하는 방법으로, HTML과 비슷한 태그 기반 형식으로 UI를 구성하고, Kotlin(Java) 코드와 결합해 화면을 만들 수 있다.  <br><br></p>
<ul>
<li><p>UI를 레이아웃 파일에서 정의 </p>
</li>
<li><p>Kotlin(Java)에서 findViewById나 View Binding으로 접근</p>
</li>
<li><p>뷰 계층이 존재하여 UI가 트리 구조로 렌더링</p>
</li>
<li><p>여러 개의 파일로 분리되어 코드와 UI를 명확히 분리 가능<br><br></p>
</li>
</ul>
<pre><code>&lt;LinearLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:orientation=&quot;vertical&quot;&gt;

    &lt;TextView
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot;Hello, XML!&quot;
        android:textSize=&quot;20sp&quot;/&gt;
&lt;/LinearLayout&gt;
</code></pre><ul>
<li>코드와 UI가 분리되어 관리해야 함 </li>
<li>레이아웃이 복잡하면 성능 저하 → 계층이 깊어질수록 렌더링 속도 느려짐</li>
<li>동적인 UI 작성이 불편함 </li>
</ul>
<br>

<h3 id="💠jetpack-compose">💠Jetpack Compose</h3>
<p>Jetpack Compose는 Kotlin 기반의 최신 UI 툴킷으로, 기존 XML 방식이 아닌 선언형 UI 개발을 가능하게 해주는 안드로이드 공식 UI 프레임워크이다. 
<Br></p>
<ul>
<li><p>코드가 간결하고 직관적</p>
<ul>
<li><p>XML 없이 Kotlin 코드만으로 UI 작성 가능</p>
</li>
<li><p>@Composable 함수로 UI를 재사용 가능</p>
</li>
<li><p>뷰 바인딩(View Binding) 불필요 → findViewById() 안 써도 됨</p>
<br>


</li>
</ul>
</li>
</ul>
<pre><code>@Composable
fun Greeting() {
    Text(text = &quot;Hello, Compose!&quot;)
}</code></pre><p>  👉 <mark>XML과 View Binding 없이 한 줄로 UI를 만들 수 있다!</mark></p>
  <br>

<ul>
<li><p>상태 관리가 쉬움</p>
<ul>
<li>UI와 데이터 연동이 직관적 <br>
</li>
</ul>
</li>
<li><p>퍼포먼스 최적화 (효율적인 UI 렌더링)</p>
<ul>
<li><p>불필요한 뷰 계층 제거 → 성능 향상</p>
</li>
<li><p>Recomposition 최적화 → 변경된 부분만 다시 그림</p>
</li>
<li><p>XML보다 빠르게 UI 렌더링 가능</p>
</li>
</ul>
<br>


</li>
</ul>
<ul>
<li><p>기존 XML과 완전히 다른 UI 개발 방식이기에 ComposeView를 사용하여 XML과 Compose 혼합 가능하지만 완전한 전환은 어렵다는 단점이 존재</p>
<br>

<hr>
<br>
🚩 Jetpack Compose는 안드로이드의 새로운 UI 개발 방식으로, 기존 XML보다 더 간결하고 직관적이며, 성능이 향상된 최신 기술이기에 안드로이드 개발을 깊이 배우고 싶다면 Jetpack Compose는 필수!!

<p>앞으로 Jetpack Compose를 더 깊이 공부하고, 실전 프로젝트에서도 활용해보도록 하겠다 (oﾟvﾟ)ノ</p>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>