Multiple choices in a list with compose

Multiple choices in a list with compose

Jetpack Compose is Android’s modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

Mutliple choices in a list with compose

you have a list with compose it is easier and if you want to do multiple choices in a list with compose you have to use rememberSaveable.

When you use compose you have to set up the gradl like this:

kotlinOptions {
jvmTarget = ‘1.8’
useIR = true
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion “1.0.0-beta08”
}
}

dependencies {

implementation ‘androidx.core:core-ktx:1.5.0’
implementation ‘androidx.appcompat:appcompat:1.3.0’
implementation ‘com.google.android.material:material:1.3.0’
implementation ‘androidx.constraintlayout:constraintlayout:2.0.4’
testImplementation ‘junit:junit:4.13.2’
androidTestImplementation ‘androidx.test.ext:junit:1.1.2’
androidTestImplementation ‘androidx.test.espresso:espresso-core:3.3.0’

// Compose
implementation “org.jetbrains.kotlin:kotlin-stdlib:1.0.0-beta08”
implementation “androidx.activity:activity-compose:1.3.0-beta01”
implementation “androidx.compose.runtime:runtime:1.0.0-beta08”
implementation “androidx.compose.ui:ui:1.0.0-beta08”
implementation “androidx.compose.foundation:foundation:1.0.0-beta08”
implementation “androidx.compose.foundation:foundation-layout:1.0.0-beta08”
implementation “androidx.compose.material:material:1.0.0-beta08”
implementation “androidx.compose.runtime:runtime-livedata:1.0.0-beta08”
implementation “androidx.compose.ui:ui-tooling:1.0.0-beta08”
implementation “com.google.android.material:compose-theme-adapter:1.0.0-beta08”
}
Share

While remember helps you retain state across recompositions, the state is not retained across configuration changes. For this, you must use rememberSaveable. rememberSaveable automatically saves any value that can be saved in a Bundle. For other values, you can pass in a custom saver object.

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.Surface
import androidx.compose.material.TabRowDefaults.Divider
import androidx.compose.material.Text
import androidx.compose.material.Checkbox
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApp {
                MyScreenContent()
            }
        }
    }
}

@Composable
fun MyApp(content: @Composable () -> Unit) {
    Surface(color = Color.White) {
        content()
    }
}

@Composable
fun MyScreenContent(
    names: List<String> = List(15) { "Item #$it" },
    completed: MutableList<Boolean> = MutableList(15) { false }
) {
    Column(modifier = Modifier.fillMaxHeight()) {
        NameList(names, Modifier.weight(1f), completed)
    }
}

@Composable
fun NameList(names: List<String>, modifier: Modifier, completed: MutableList<Boolean>) {
    LazyColumn(modifier = modifier) {
        itemsIndexed(items = names) { index: Int, item: String ->
            Greeting(name = item, completed, index)
            Divider(color = Color.Black)
        }
    }
}

@Composable
fun Greeting(name: String, completedList: MutableList<Boolean>, index: Int) {
    var isSelected by rememberSaveable { mutableStateOf(completedList[index]) }
    val backgroundColor by animateColorAsState(if (isSelected) Color.Blue else Color.Transparent)

    Row {
        Text(
            text = "Hello $name!",
            modifier = Modifier
                .padding(24.dp)
        )
        Checkbox(
                checked = isSelected,
                onCheckedChange = {
                    isSelected = !isSelected
                    completedList[index] = !isSelected
                },
                modifier = Modifier
                    .background(color = backgroundColor)
            )
        }
    }


@Preview("MyScreen preview")
@Composable
fun DefaultPreview() {
    MyApp {
        MyScreenContent()
    }
}

you can download in Github

Fast scroll in ListView

Fast scroll in ListView

Sometimes when the list is very big, We need to make a fast scroll view. FastScroll is something like that:

Now we leart how to make a fast scroll in listView.
We need these things:

-Style in values-v14.
-Style.
-Colors.
-Layout.
-An adapter for list.
-Activity.

in directory values-v14/styles.xml we have to add three things:
fastScrollThumbDrawable
fastScrollTextColor
fastScrollPreviewBackgroundRight

<?xml version="1.0" encoding="utf-8"?>
<resources>
 
    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
        <!-- API 14 theme customizations can go here. -->
        <item name="android:fastScrollThumbDrawable">@drawable/fastscroll_thumb_holo</item>
        <item name="android:fastScrollTextColor">@android:color/white</item>
        <item name="android:fastScrollPreviewBackgroundRight">@color/apptheme_color</item>
    </style>
 
</resources>

In directory values/styles.xml

<resources>
 
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:fastScrollThumbDrawable">@drawable/fastscroll_thumb_holo</item>
        <item name="android:fastScrollTextColor">@android:color/white</item>
        <item name="android:fastScrollPreviewBackgroundRight">@color/apptheme_color</item>
    </style>
 
</resources>

In Colors we have to add one color:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="apptheme_color">#DA4A38</color>
</resources>

You can doing without style, so you can skip last steps, and start since here:

The color of the indicator is your colorAccent

You can find the complete code in GitHub

res/layout/list_item

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="40dp" />

In activity_layout our listView.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.javier.fastscrollerwithandroidstyle.MainActivity">
 
    <ListView
        android:id="@+id/activity_main_list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scrollbarStyle="outsideOverlay" />
</RelativeLayout>

Our ListAdapter

public class ListAdapter extends ArrayAdapter<String> implements SectionIndexer {
 
    HashMap<String, Integer> mapIndex;
    String[] sections;
    List<String> fruits;
 
    public ListAdapter(Context context, List<String> fruitList) {
        super(context, R.layout.list_item, fruitList);
 
        this.fruits = fruitList;
        mapIndex = new LinkedHashMap<String, Integer>();
 
        for (int x = 0; x < fruits.size(); x++) {
            String fruit = fruits.get(x);
            String ch = fruit.substring(0, 1);
            ch = ch.toUpperCase(Locale.US);
 
            // HashMap will prevent duplicates
            mapIndex.put(ch, x);
        }
 
        Set<String> sectionLetters = mapIndex.keySet();
 
        // create a list from the set to sort
        ArrayList<String> sectionList = new ArrayList<String>(sectionLetters);
 
        Log.d("sectionList", sectionList.toString());
        Collections.sort(sectionList);
 
        sections = new String[sectionList.size()];
 
        sectionList.toArray(sections);
    }
 
    public int getPositionForSection(int section) {
        Log.d("section", "" + section);
        return mapIndex.get(sections[section]);
    }
 
    public int getSectionForPosition(int position) {
        Log.d("position", "" + position);
        return 0;
    }
 
    public Object[] getSections() {
        return sections;
    }
}

In our activity

public class MainActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        ListView listView = (ListView) findViewById(R.id.activity_main_list);
        listView.setFastScrollEnabled(true);
        String[] fruits = getResources().getStringArray(R.array.fruits_array);
 
        List<String> fruitList = Arrays.asList(fruits);
        ListAdapter listAdapter = new ListAdapter(this, fruitList);
        listView.setAdapter(listAdapter);
 
    }
}

And in our strings, something like that:

<resources>
    <string name="app_name">FastScrollerWithAndroidStyle</string>
    <string-array name="fruits_array">
        <item>Apples</item>
        <item>Apricots</item>
        <item>Avocado</item>
        <item>Annona</item>
        <item>Banana</item>
        <item>Bilberry</item>
        <item>Blackberry</item>
        <item>Custard Apple</item>
        <item>Clementine</item>
        <item>Cantalope</item>
        <item>Coconut</item>
        <item>Currant</item>
        <item>Cherry</item>
        <item>Cherimoya</item>
        <item>Date</item>
        <item>Damson</item>
        <item>Durian</item>
        <item>Elderberry</item>
        <item>Fig</item>
        <item>Feijoa</item>
        <item>Grapefruit</item>
        <item>Grape</item>
        <item>Gooseberry</item>
        <item>Guava</item>
        <item>Honeydew melon</item>
        <item>Huckleberry</item>
        <item>Jackfruit</item>
        <item>Juniper Berry</item>
        <item>Jambul</item>
        <item>Jujube</item>
        <item>Kiwi</item>
        <item>Kumquat</item>
        <item>Lemons</item>
        <item>Limes</item>
        <item>Lychee</item>
        <item>Mango</item>
        <item>Mandarin</item>
        <item>Mangostine</item>
        <item>Nectaraine</item>
        <item>Orange</item>
        <item>Olive</item>
        <item>Prunes</item>
        <item>Pears</item>
        <item>Plum</item>
        <item>Pineapple</item>
        <item>Peach</item>
        <item>Papaya</item>
        <item>Passionfruit</item>
        <item>Pomegranate</item>
        <item>Pomelo</item>
        <item>Raspberries</item>
        <item>Rock melon</item>
        <item>Rambutan</item>
        <item>Strawberries</item>
        <item>Sweety</item>
        <item>Salmonberry</item>
        <item>Satsuma</item>
        <item>Tangerines</item>
        <item>Tomato</item>
        <item>Ugli</item>
        <item>Watermelon</item>
        <item>Woodapple</item>
    </string-array>
</resources>

You can find the complete code in GitHub