Compose Verse에 들어가면 Jetpack Compose를 사용한 안드로이드 개발 초보자 가이드


제1부분: 가장 기본적인.
무엇
안드로이드 개발의 주요 특징은 보기를 바탕으로 하는 안드로이드 사용자 인터페이스로 시스템을 구축하는 것이다.이 방법은 UI 요소와 레이아웃을 XML 파일의 보기로 정의한 다음 확장된 보기를 통해 이러한 보기를 보여 주고 사용자에게 그것들과 상호작용할 수 있는 능력을 부여하는 것과 관련이 있다.창설된 보기는 일반적으로 일부 상태를 포함하고, 보기는 사용자의 상호작용에 따라 상태를 변경합니다.
위의 시스템은 애플리케이션을 구축하기 위한 좋은 방법인 것 같은데 왜 변경해야 하는가? 뷰 기반 방법에는 두 가지 문제가 있습니다.
그것은 매우 오래되었다.안드로이드 뷰 시스템은 십여 년 전에 만들어졌기 때문에 API가 노화의 징후를 보이기 시작했고 뷰 시스템의 프로그래밍 패턴에 큰 영향을 미쳤기 때문에 오늘날에는 그다지 두드러지지 않는다.보기 시스템의 노화를 나타내는 두드러진 예는 사용자 인터페이스 구성 요소의 기본 구조 블록을 나타내는 보기 종류가 30000줄을 넘는다는 것이다.androidtoolkit팀은 심지어 이 클래스의 코드 수량이 관리할 수 없기 때문에 변경이 필요하다고 밝혔다.
  • 사용자가 사용자 인터페이스에 대한 기대가 점점 높아지고 있다.androidview 시스템이 출시된 이래로 사용자들이 사용자 인터페이스에 대한 각종 수요가 이미 크게 증가하였다.사용자는 뷰 시스템을 처음 개발할 때 별로 중요하지 않은 애니메이션, 동작이 있는 UI를 선호합니다.
  • 복잡성.보기 시스템은 XML로 사용자 인터페이스를 작성하고 자바나 Kotlin으로 응용 프로그램 논리를 작성합니다.이것은 불가피하게 관리 응용 프로그램의 의외의 복잡성을 초래했다.그 밖에 XML의 특성 때문에 우리는 더 긴 코드 줄을 작성해서 작은 일을 완성해야 한다. 예를 들어 크리스털 공장의 모양을 바꾸거나 버튼에 점차적인 변화를 적용하는 간단한 일은 그릴 수 있는 XML 파일을 만들고 점차적인 변화를 버튼에 적용하기 전에 수동으로 점차적인 변화를 정의해야 한다.
  • 아무도 XML을 좋아하지 않아요.😉)
  • 무엇
    이러한 문제를 해결하기 위해 Android UI 팀은 Jetpack Compose를 도입했습니다.Jetpack compose는 Android가 네이티브 UI를 구축하는 데 사용하는 현대 키트입니다.이것은android의 UI 개발을 간소화하고 가속화하며, 더 적은 코드와 직관적인 Kotlin API로 프로그램을 신속하게 생활로 가져올 수 있도록 합니다.
    Jetpack Compose는 Kotlin 을 사용하여 작성되었으며, 하나의 언어로 더 빠르고 간단한 개발을 제공하였으며, 코드 줄은 더욱 적습니다.android 스튜디오와 기타 jetpack 제품도 지원합니다.그래서 우리의 발전 속도가 크게 높아졌다.Jetpack Compose는 명시적인 UI 방법을 제공합니다.
    compose는 어떤 문제를 해결했습니까?
  • 관심점 분리: 보기 시스템을 사용할 때 우리는 응용 프로그램 논리와 레이아웃 파일 등 각종 요소를 긴밀하게 결합시킨다.이것은 코드에서 불필요한 복잡성을 초래할 수 있다.jetpack compose를 사용할 때 우리의 레이아웃과 응용 프로그램 논리는 모두 같은 언어로 정의되어 우리의 요소 간의 의존성이 더욱 뚜렷해지기 때문에 우리는 요소 간의 결합을 쉽게 재구성하고 줄일 수 있다.Jetpack compose는 관심 분야를 보다 효과적으로 분리할 수 있는 도구를 제공합니다.
  • Kotlin 언어의 힘을 UI 요소에 도입합니다.Jetpack Compose는 순수히kotlin이기 때문에, 우리는kotlin이 제공하는 언어급 원어를 사용하여 동작을 동적으로 실행할 수 있습니다. 예를 들어if-else 문구를 사용하여 일부 UI를 나타내거나 복잡한 UI 논리를 쉽게 실행할 수 있습니다.보기 시스템을 사용하면 이 정도는 할 수 있지만 본질적으로 더 복잡하다. 먼저 XML 파일의 모든 UI 요소를 정의한 다음, 활동이나 세션의 Id나 보기 연결을 통해 이 요소를 찾은 다음, 거기에서 우리의 제어 흐름 논리를 실행해야 하기 때문이다.jetpack compose에서, 우리는 더 적은 코드로 한 파일에서 이 모든 것을 완성할 수 있다.
  • 상속이 아니라 구도를 좋아한다.뷰 시스템은 상속을 바탕으로 구축된 것으로 모든 UI 요소는 뷰 클래스에서 상속됩니다. 내장 뷰를 확장하여 사용자 정의 요소를 만들 수 있지만 상속과 관련된 모든 문제를 일으킬 수 있습니다.Compose에서 우리는 단일한 부모 요소를 계승할 필요가 없다. 우리의 모든 Ui 요소는 다른 Ui 요소로 구성되어 있기 때문에 우리는 자신의 취향에 따라 전환하거나 수정할 수 있다.

  • 뷰 및 작성
    현재 일부 이론은 이미 시대에 뒤떨어졌다. 보기 시스템과 Jetpack Compose를 이용하여 UI를 구축하는 실제 예를 살펴보자.뷰 시스템과 Jetpack compose로 다음 UI를 다시 만들고 어느 것이 더 이상적인지 비교할 수 있기 때문에 부릉이를 준비할 것입니다.
    UI we will be building

    뷰 시스템
    뷰 시스템을 사용하여 위의 UI를 구축하려면 다음과 같은 방법을 사용합니다.
  • 회수기 보기
  • 사용자 정의 뷰 어댑터
  • 구글 재료 카드 보기
  • 구글 재질 버튼

  • 1단계:레이아웃
    주요 활성 XML에 recycler 보기와 필요한 제약조건이 추가되었습니다.
    <?xml version="1.0" encoding="utf-8"?> 
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        xmlns:app="http://schemas.android.com/apk/res-auto" 
        xmlns:tools="http://schemas.android.com/tools" 
        android:layout_width="match_parent" 
        android:layout_height="match_parent" 
        tools:context=".MainActivity"> 
        <androidx.recyclerview.widget.RecyclerView 
            android:id="@+id/main_recycler_view" 
            android:layout_width="match_parent" 
            android:layout_height="match_parent" 
            app:layout_constraintBottom_toBottomOf="parent" 
            app:layout_constraintLeft_toLeftOf="parent" 
            app:layout_constraintRight_toRightOf="parent" 
            app:layout_constraintTop_toTopOf="parent" /> 
    </androidx.constraintlayout.widget.ConstraintLayout>
    
    다음에 목록에 있는 카드마다 레이아웃을 만듭니다
    <?xml version="1.0" encoding="utf-8"?> 
    <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" 
        xmlns:app="http://schemas.android.com/apk/res-auto" 
        xmlns:tools="http://schemas.android.com/tools" 
        android:id="@+id/meal_card" 
        android:layout_width="match_parent" 
        android:layout_height="wrap_content" 
        app:cardCornerRadius="10dp" 
        app:cardElevation="5dp" 
        app:cardUseCompatPadding="true"> 
        <LinearLayout 
            android:layout_width="match_parent" 
            android:layout_height="match_parent" 
            android:orientation="vertical"> 
            <ImageView 
                android:id="@+id/meal_image" 
                android:layout_width="match_parent" 
                android:layout_height="150dp" 
                android:scaleType="centerCrop" 
                tools:src="@drawable/pizza" /> 
            <TextView 
                android:id="@+id/meal_name" 
                android:layout_width="wrap_content" 
                android:layout_height="wrap_content" 
                android:paddingStart="10dp" 
                android:text="Hello world" 
                android:textSize="20sp" 
                android:textStyle="bold" /> 
            <LinearLayout 
                android:layout_width="match_parent" 
                android:layout_height="wrap_content" 
                android:gravity="bottom" 
                android:orientation="horizontal" 
                android:padding="10dp"> 
                <TextView 
                    android:id="@+id/meal_time" 
                    android:layout_width="wrap_content" 
                    android:layout_height="wrap_content" 
                    android:text="5mins" 
                    android:textSize="20sp" /> 
                <View 
                    android:layout_width="10dp" 
                    android:layout_height="match_parent" /> 
                <TextView 
                    android:id="@+id/meal_ingredients" 
                    android:layout_width="wrap_content" 
                    android:layout_height="wrap_content" 
                    android:text="4 ingredients" 
                    android:textSize="20sp" /> 
                <View 
                    android:layout_width="15dp" 
                    android:layout_height="match_parent" /> 
                <com.google.android.material.button.MaterialButton 
                    style="@style/Widget.MaterialComponents.Button.OutlinedButton" 
                    android:layout_width="wrap_content" 
                    android:layout_height="wrap_content" 
                    android:background="@android:color/white" 
                    android:drawableLeft="@drawable/ic_baseline_play_arrow" 
                    android:drawableTint="@color/green" 
                    android:text="cook" 
                    android:textColor="@color/green" 
                    android:textSize="15sp" 
                    app:strokeColor="@color/green" 
                    app:strokeWidth="20dp" /> 
            </LinearLayout> 
        </LinearLayout> 
    </androidx.cardview.widget.CardView>
    

    2단계: 어댑터
    우리의 회수기 보기에 사용할 사용자 정의 어댑터를 만듭니다
    class MealAdapter() : RecyclerView.Adapter<MealAdapter.ViewHolder>() { 
        private var meals = emptyList<Meal>() 
        class ViewHolder(binding: MealCardBinding) : RecyclerView.ViewHolder(binding.root) { 
            val image = binding.mealImage 
            val name = binding.mealName 
            val time = binding.mealTime 
            val noIngredients = binding.mealIngredients 
        } 
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 
            val binding: MealCardBinding = MealCardBinding.inflate( 
                LayoutInflater.from(parent.context), 
                parent, 
                false 
            ) 
            return ViewHolder(binding) 
        } 
        @SuppressLint("SetTextI18n") 
        override fun onBindViewHolder(holder: ViewHolder, position: Int) { 
            val meal = meals[position] 
            holder.image.setImageResource(meal.image) 
            holder.name.text = meal.name 
            holder.time.text = "${meal.time} minutes" 
            holder.noIngredients.text = "${meal.ingredients} ingredients" 
        } 
        override fun getItemCount(): Int { 
            return meals.size 
        } 
        @SuppressLint("NotifyDataSetChanged") 
        fun updateMeals(meals: List<Meal>) { 
            Log.i("test", meals.toString()) 
            this.meals = meals 
            notifyDataSetChanged() 
        } 
    }
    

    3단계: 모델 및 상태 보기
    UI에 표시될 데이터와 상태 클래스를 저장하는 보기 모델이 필요합니다. 편의를 위해 식사 대상을 미리 불러옵니다.
    식사 모드
    data class Meal (val name: String, val time: Int, val ingredients: Int, val image: Int)
    
    식사 상태
    data class MealState(
        val meals: List<Meal> = listOf(
            Meal(
                name = "Cooked Coconut Mussels",
                time = 5,
                ingredients = 4,
                image = R.drawable.cookedcoconutmussels
            ),
            Meal(
                name = "Banana and Mandarin Buns",
                time = 45,
                ingredients = 6,
                image = R.drawable.bananaandmandarinbuns
            ),
            Meal(name = "Strawberry Meal", time = 59, ingredients = 3, image = R.drawable.strawberries),
            Meal(
                name = "Pizza",
                time = 50,
                ingredients = 7,
                image = R.drawable.pizza
            )
    
        )
    )
    
    식사 보기 모형
    class MealViewModel : ViewModel() { 
        private val _state = MutableLiveData(MealState()) 
        val state: LiveData<MealState> 
            get() = _state 
    }
    

    4단계:모든 물건을 한데 놓다
    우리의 주요 활동 클래스에서, 우리는 어댑터를 사용하여recycler 보기를 설정하고, 우리의 필기 상태를 관찰한다
    class MainActivity : AppCompatActivity() { 
        private lateinit var binding: ActivityMainBinding 
        private val mealViewModel: MealViewModel by viewModels() 
        override fun onCreate(savedInstanceState: Bundle?) { 
            super.onCreate(savedInstanceState) 
            binding = ActivityMainBinding.inflate(layoutInflater) 
            setContentView(binding.root) 
            val adapter: MealAdapter = MealAdapter() 
            binding.mainRecyclerView.adapter = adapter 
            binding.mainRecyclerView.layoutManager = LinearLayoutManager(this) 
            mealViewModel.state.observe(this, Observer { mealState -> 
                adapter.updateMeals(mealState.meals) 
            }) 
        } 
    }
    
    생성된 UI는 다음과 같습니다.
    Image of the resulting UI made with the view system 1


    에어백
    jetpack compose를 사용하여 프로젝트를 만들려면 Android Studio를 열고 새 프로젝트를 선택한 다음 제공된 템플릿에서 empty compose activity를 선택합니다.이것은 모든 의존항 설정을 포함하는compose 프로젝트를 생성합니다.
    Jetpack compose를 사용하면 Composables를 사용하여 사용자 인터페이스를 만들 수 있습니다.이것들은 @Composable 주석을 사용하는 간단한 함수입니다.
    일단 우리가 조합할 수 있는 함수가 생기면, 우리는 수식자로 그것의 행위를 설계하거나 수정할 수 있다.수식자는 우리가 조합 가능한 함수에 전달하는 매개 변수로, 조합 가능한 함수의 표시 방식을 바꾸는 데 도움을 준다.
    우리는 수식자를 사용하여 다음과 같은 조작을 수행할 수 있다.
  • 구성 요소의 행동과 외관 변경
  • 액세스 가능성 레이블 등 추가 정보
  • 요소를 클릭, 스크롤, 드래그 또는 확대/축소할 수 있는 고급 상호 작용을 추가합니다.
    뷰 기반 레이아웃의 레이아웃 매개변수와 매우 비슷합니다.
  • jetpack compose에서 UI를 구축하려면 먼저 다음 종속성을 추가합니다.
  • Jetpack 콤보 보기 모델 의존 항목, UI 데이터 관리용
  • 재료 아이콘
  • 슬라이딩을 통한 간편한 이미지 처리

  • 단계 1: 종속성 추가
    프로젝트에서Gradle 파일은 구축 스크립트에 다음 내용을 추가합니다
        ext { 
            compose_version = '1.0.1' 
        }
    
    다음 단계는 응용 프로그램Gradle 파일입니다
      //compose dependencies 
    implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0-beta01"
    implementation "androidx.compose.material:material-icons-extended:$compose_version"
    implementation "com.github.skydoves:landscapist-glide:1.4.5"
    

    2단계: 모델 및 상태 보기
    data class Meal( 
        val name: String, 
        val image: Int, 
        val ingredients: Int, 
        val time: Int 
    )
    
    data class MealState( 
        val recipes: List<Meal> = listOf( 
            Meal( 
                "Banana and Mandarin buns", 
                R.drawable.bananaandmandarinbuns, 
                5, 
                20 
            ), 
            Meal( 
                "Cooked Coconut Mussels", 
                R.drawable.cookedcoconutmussels, 
                7, 
                11 
            ), 
            Meal( 
                "Fancy", 
                R.drawable.feedimage2, 
                9, 
                11, 
            ), 
            Meal( 
                "Italian", 
                R.drawable.pizza, 
                4, 
                20 
            ), 
        ), 
    )
    
    class MealViewModel : ViewModel(){ 
        private val _state = mutableStateOf(MealState()) 
        val state = _state 
    }
    
    주의: 보기 모델에서 우리는 실시간 데이터가 아닌 가변 상태를 사용합니다. 이것은 jetpack compose가 우리에게 새로운 상태 API를 제공했기 때문입니다. 이것은 실시간 데이터 API와 유사하지만, 이러한 상태를 직접 관찰할 필요가 없습니다. jetpack compose는 막후에서 이 상태에서 읽을 수 있는 모든 조합에서 이 상태에서 보내는 쓰기 동작까지 구독합니다.따라서 상태 객체에서 읽은 조합 가능한 모든 객체는 알림을 받고 수정 시 새 데이터를 사용하여 다시 그려집니다.

    3단계: 조합식 카드 만들기
    @Composable 
    fun MealCard( 
        meal: Meal, 
    ) { 
        Card(modifier = Modifier.height(250.dp)) {
    
            Column(modifier = Modifier.fillMaxSize()) { 
                Box( 
                    modifier = Modifier 
                        .fillMaxHeight(fraction = 0.5f) 
                        .fillMaxWidth() 
                ) { 
                    GlideImage( 
                        imageModel = meal.image, 
                        contentDescription = meal.name, 
                        modifier = Modifier 
                            .matchParentSize() 
                            .clip( 
                                RoundedCornerShape( 
                                    topStart = 5.dp, 
                                    topEnd = 5.dp 
                                ) 
                            ), 
                        contentScale = ContentScale.Crop 
                    ) 
                } 
                Spacer(modifier = Modifier.width(10.dp)) 
                Column( 
                    modifier = Modifier 
                        .fillMaxWidth() 
                        .padding(10.dp), 
                    ) { 
                    Text( 
                        text = meal.name, 
                        fontWeight = FontWeight(600), 
                        fontSize = 18.sp 
                    ) 
                    Spacer(modifier = Modifier.height(10.dp)) 
                    Row( 
                        modifier = Modifier.fillMaxWidth(), 
                        horizontalArrangement = Arrangement.SpaceBetween, 
                        verticalAlignment = Alignment.CenterVertically 
                    ) { 
                        Row( 
                        ) { 
                            Text(text = "${meal.time} minutes", color = Color.Black) 
                            Spacer(modifier = Modifier.width(10.dp)) 
                            Text(text = "${meal.ingredients} Ingredients", color = Color.Black) 
                        } 
                        OutlinedButton( 
                            onClick = {}, 
                            border = BorderStroke(1.dp, Color.Green) 
                        ) { 
                            Row(verticalAlignment = Alignment.CenterVertically) { 
                                Icon( 
                                    imageVector = Icons.Outlined.PlayArrow, 
                                    contentDescription = null, 
                                    tint = Color.Green 
                                ) 
                                Text(text = "Cook", color = Color.Green) 
                            } 
                        } 
                    } 
                } 
            } 
        } 
    }
    
    위의 식카드에서 우리는 제공된 내장 조합을 사용하여 우리의 식카드 조합을 구축하고 수정기를 광범위하게 사용하여 우리의 수요에 따라 맞춤형 조합을 만든다.우리가 위에서 사용한 복합어와 수식어는
  • 카드: 기본 높이와 각 반지름이 포함된 내장형 조합입니다.
  • 열: 내용을 수직열
  • 에 배치
  • GlideImage: 이것은 glide 라이브러리에서 조합할 수 있는 이미지로 우리가 이미지를 표시하고 디자인하는 데 도움을 준다
  • 간격: 원소 사이에 공간을 만들 뿐입니다
  • 줄: 내용을 수평줄에 배치
  • 현재 가장 좋은 부분은 Jetpack Compose를 사용하면 동적 크기의 목록을 언제 보여야 하든지 휴지통 보기나 어댑터를 만들 걱정은 하지 않고 아래와 같은 타성열이나 타성행 조합만 사용하면 된다는 것이다
    @Composable 
    fun App( 
        mealViewModel: MealViewModel = viewModel(), 
    ) { 
        val state = mealViewModel.state.value 
        LazyColumn(modifier = Modifier 
            .fillMaxSize() 
            .padding(20.dp)) { 
            items(state.recipes) { item: Meal -> 
                MealCard(meal = item) 
                Spacer(modifier = Modifier.height(16.dp)) 
            } 
        } 
    }
    

    4단계: 이 모든 것을 주요 활동에 두다
    class MainActivity : ComponentActivity() { 
        override fun onCreate(savedInstanceState: Bundle?) { 
            super.onCreate(savedInstanceState) 
            setContent { 
                JetpackComposeExampleTheme { 
                    App() 
                } 
            } 
        } 
    }
    
    생성된 UI
    Resulting UI Built with Jetpack compose 1


    판결하다
    Jetpack compose는 설명식 UI를 단일 언어로 구성하는 방법을 제공합니다.Kotlin의 강력한 기능을 이용하여 더 적은 코드 줄로 복잡한 UI를 만들고 프로그램의 다른 부분에 집중할 수 있도록 합니다.조합 주석
    서로 다른 기능으로 UI를 구축하면 우리는 임의로 교환하고 조작할 수 있으며 Jetpack compose가 제공하는 상태 API는 응용 프로그램의 상태를 보다 간단하고 직관적으로 관리하는 방법을 제공한다.
    본 문서에 사용된 코드 예는 다음과 같습니다.
    Source Code

    좋은 웹페이지 즐겨찾기