DEMO VIDEO:
First, define a simple activity layout file (xml), only includes a ListView:
The most important work will be done in ListView adapter class (extends from ArrayAdapter class). In this, define a int variable called selectedPosition by defaul value is -1. When we checked at each CheckBox, it's value will be changed to row's postion and restore to the default values when unchecked. So, we have this method:
private View.OnClickListener onStateChangedListener(final CheckBox checkBox, final int position) { return new View.OnClickListener() { @Override public void onClick(View v) { if (checkBox.isChecked()) { selectedPosition = position; } else { selectedPosition = -1; } notifyDataSetChanged(); // update adapter after changed } }; }In getView() method (override from parent class), set event for CheckBox through call:
holder.checkBox.setOnClickListener(onStateChangedListener(holder.checkBox, position));Important Note: Always use setOnClickListener() for CheckBox instead of setOnCheckedChangeListener() because of recycling feature of ListView, the first rows cannot be checked!
Provide a ViewHolder class to get scroll smoother, we have full code for this adapter class:
package info.devexchanges.singlchecklistview; import android.app.Activity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.TextView; import java.util.List; public class ListViewAdapter extends ArrayAdapter<Friend> { private List<Friend> myFriends; private Activity activity; private int selectedPosition = -1; public ListViewAdapter(Activity context, int resource, List<Friend> objects) { super(context, resource, objects); this.activity = context; this.myFriends = objects; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE); // If holder not exist then locate all view from UI file. if (convertView == null) { // inflate UI from XML file convertView = inflater.inflate(R.layout.item_listview, parent, false); // get all UI view holder = new ViewHolder(convertView); // set tag for holder convertView.setTag(holder); } else { // if holder created, get tag from view holder = (ViewHolder) convertView.getTag(); } holder.checkBox.setTag(position); // This line is important. holder.friendName.setText(getItem(position).getName()); if (position == selectedPosition) { holder.checkBox.setChecked(true); } else holder.checkBox.setChecked(false); holder.checkBox.setOnClickListener(onStateChangedListener(holder.checkBox, position)); return convertView; } private View.OnClickListener onStateChangedListener(final CheckBox checkBox, final int position) { return new View.OnClickListener() { @Override public void onClick(View v) { if (checkBox.isChecked()) { selectedPosition = position; } else { selectedPosition = -1; } notifyDataSetChanged(); } }; } private static class ViewHolder { private TextView friendName; private CheckBox checkBox; public ViewHolder(View v) { checkBox = (CheckBox) v.findViewById(R.id.check); friendName = (TextView) v.findViewById(R.id.name); } } }In activity, I get a dummy data set from text file in Assests to create a List object use for ListView then. Set header for our ListView, handling each item click event,...we have full code:
package info.devexchanges.singlchecklistview; import android.app.Dialog; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.method.CharacterPickerDialog; import android.view.LayoutInflater; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { private ArrayList<Friend> friendArrayList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); friendArrayList = new ArrayList<>(); ListView listView = (ListView) findViewById(R.id.list_item); //set ListView header LayoutInflater inflater = getLayoutInflater(); View header = inflater.inflate(R.layout.header_listview, listView, false); listView.addHeaderView(header, null, false); readDataFromAssets(); ListViewAdapter adapter = new ListViewAdapter(this, R.layout.item_listview, friendArrayList); listView.setAdapter(adapter); listView.setOnItemClickListener(onItemClickListener()); } private AdapterView.OnItemClickListener onItemClickListener() { return new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { final Dialog dialog = new Dialog(MainActivity.this); dialog.setContentView(R.layout.layout_dialog); dialog.setTitle("Friend Details"); dialog.setCancelable(true); TextView friendID = (TextView) dialog.findViewById(R.id.position); TextView friendName = (TextView) dialog.findViewById(R.id.name); friendID.setText("Position: " + (position + 1)); friendName.setText("Name: " + ((Friend) parent.getItemAtPosition(position)).getName()); dialog.show(); } }; } private void readDataFromAssets() { BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(getAssets().open("friend.txt"))); // do reading, usually loop until end of file reading String line; while ((line = reader.readLine()) != null) { friendArrayList.add(new Friend(line)); } } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } } }Output when app running:
Finally, there are some necessary files to complete this project:
- A layout for each ListView item, contains a CheckBox and a TextView:
Note: Always set android:focusable="false" property to CheckBox if you want ListView row clickable!
- A Dialog layout (show on each item clicked):
Output:
- In activity code, we added a header layout for ListView, so this is it xml file:
Conclusions: There are a lot of ways to make this trick in ListView with CheckBox, my solution is just only one of them. By searching on Internet, you'll find out another quickly. Hoping my simple project in this tip is helpful!