29.ноя.2024

Android разработка, переход с View на Compose

Переделка проекта на Jetpack Compose может значительно упростить работу с пользовательским интерфейсом, но требует изменения подхода к архитектуре, так как Compose работает декларативно. Если у вас есть Fragment и Adapter (например, для RecyclerView), их можно адаптировать под Compose. Вот пошаговая инструкция:



1. Замена Fragment на Composable

Fragment обычно используется для управления частью пользовательского интерфейса. В Compose вместо фрагментов используются функции-компоненты @Composable.

Пример:

Ваш существующий фрагмент:

class ExampleFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_example, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // Инициализация элементов
    }
}

Переделка:

  1. Создайте @Composable-функцию для экрана:

@Composable
fun ExampleScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        Text(
            text = "Hello from Compose!",
            style = MaterialTheme.typography.h5
        )
        Button(onClick = { /* Handle click */ }) {
            Text(text = "Click Me")
        }
    }
}
  1. В Activity замените вызов FragmentTransaction на вызов setContent:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ExampleScreen()
        }
    }
}

Теперь ExampleScreen заменяет ваш Fragment.



2. Замена RecyclerView.Adapter на LazyColumn

Compose предоставляет компонент LazyColumn для создания списков. Он заменяет RecyclerView.

Существующий адаптер:

class ExampleAdapter(private val items: List<String>) : RecyclerView.Adapter<ExampleAdapter.ViewHolder>() {
    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val textView: TextView = view.findViewById(R.id.textView)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_example, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.textView.text = items[position]
    }

    override fun getItemCount(): Int = items.size
}

Переделка в LazyColumn:

  1. Удалите адаптер.

  2. Создайте @Composable-функцию для отображения списка:

@Composable
fun ExampleList(items: List<String>) {
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        contentPadding = PaddingValues(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(items) { item ->
            ExampleListItem(item = item)
        }
    }
}

@Composable
fun ExampleListItem(item: String) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp),
        elevation = 4.dp
    ) {
        Text(
            text = item,
            modifier = Modifier.padding(16.dp),
            style = MaterialTheme.typography.body1
        )
    }
}
  1. Вызовите ExampleList из вашего экрана:

@Composable
fun ExampleScreen(items: List<String>) {
    Column(modifier = Modifier.fillMaxSize()) {
        Text(
            text = "Items List",
            style = MaterialTheme.typography.h4,
            modifier = Modifier.padding(16.dp)
        )
        ExampleList(items = items)
    }
}


3. Передача данных в Compose

Compose использует ViewModel для работы с данными. Если в Fragment использовался ViewModel, он интегрируется с Compose через viewModel().

Пример:

  1. ViewModel для списка:

class ExampleViewModel : ViewModel() {
    private val _items = MutableLiveData<List<String>>(listOf("Item 1", "Item 2", "Item 3"))
    val items: LiveData<List<String>> = _items
}
  1. Подключение ViewModel в Compose:

@Composable
fun ExampleScreen(viewModel: ExampleViewModel = viewModel()) {
    val items by viewModel.items.observeAsState(emptyList())
    ExampleList(items = items)
}


4. Управление состоянием через Compose

Compose поддерживает управление состоянием через State. Например:

@Composable
fun ExampleScreen() {
    var searchText by remember { mutableStateOf("") }
    val items = listOf("Apple", "Banana", "Cherry")
    val filteredItems = items.filter { it.contains(searchText, ignoreCase = true) }

    Column {
        TextField(
            value = searchText,
            onValueChange = { searchText = it },
            modifier = Modifier.fillMaxWidth(),
            placeholder = { Text("Search") }
        )
        ExampleList(items = filteredItems)
    }
}


5. Интеграция Jetpack Compose с существующим проектом

Если вы не хотите полностью удалять XML и Fragment, можно использовать ComposeView в существующем макете.

Пример использования ComposeView в XML:

<androidx.compose.ui.platform.ComposeView
    android:id="@+id/composeView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

В Fragment или Activity добавьте содержимое для ComposeView:

class ExampleFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val composeView = view.findViewById<ComposeView>(R.id.composeView)
        composeView.setContent {
            ExampleScreen()
        }
    }


Итоговый порядок действий для переделки:

  1. Удалите XML-разметки и замените их @Composable функциями.

  2. Удалите Fragment и используйте Composable вместо них.

  3. Замените RecyclerView на LazyColumn или LazyRow.

  4. Настройте управление состоянием через State или ViewModel.

  5. Интегрируйте Compose через setContent в Activity или используйте ComposeView в существующих макетах.

  6. Добавьте анимации и стили для улучшения UX (опционально).

← Назад к списку новостей