2.4.8 Solving the Checkbox Misalignment Issue in ListView
Category Android Basic Beginner Tutorial
Introduction:
>
As one of the classic issues with ListView, if you've tried customizing ListView items with a checkbox, you might encounter this problem when the number of items exceeds a page. Below, we'll analyze the cause of this issue and discuss how to resolve it!
1. Causes of the Issue:
Here's a diagram found online that illustrates the ListView getView method invocation mechanism:
In the diagram, there's a Recycler. The visible items on the ListView are in memory, while the items that are not visible are stored in this Recycler. When loading items for the first time, the convertView in the current page is NULL. When an item scrolls out of the screen, the ConvertView is no longer empty, so a new item will reuse this ConvertView!
We can write a simple example and follow the logs. Here are some logs after running the example:
From the logs, we can see that starting from Position 12, ConvertView is no longer empty. What this specifically represents is unclear, and it might require looking into the source code... We know that ConvertView is cached here, and it's this caching that causes the checkbox misalignment. Therefore, the first solution is to not reuse this ConvertView, or to set the ConvertView to null every time getView is called. However, if the number of items to be displayed is huge, this method would be very cumbersome. Typically, in actual development, we use the following solution: Find something to store the current item CheckBox status, and initialize it by checking and setting whether it's selected.
2. Example Solution:
>
There are many good ways to store this Checkbox status. You can use a HashMap<Integer, Boolean>, and each time you initialize, you can retrieve the corresponding boolean value based on the position and then set the Checkbox status; My approach was to add a boolean value in the entity class for checking. Below is the code extracted from one of my projects. The code is simple, and I believe you'll understand it instantly.
Entity class: Person.java:
public class Person implements Serializable {
private String name;
private String number;
private boolean checkStatus;
public Person(String name, String number) {
super();
this.name = name;
this.number = number;
this.checkStatus = false;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public boolean getCheckStatus() {
return checkStatus;
}
public void setCheckStatus(boolean checkStatus) {
this.checkStatus = checkStatus;
}
}
Implemented Adapter class: ContactListAdapter.java:
public class ContactListAdapter extends BaseAdapter implements CompoundButton.OnCheckedChangeListener {
private List<Person> mData;
private Context mContext;
public ContactListAdapter(List<Person> data, Context context) {
mData = data;
mContext = context;
}
// Method to refresh data
public void changeData(List<Person> data) {
mData = data;
notifyDataSetChanged();
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Person getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int index = position;
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(
R.layout.item_contact, parent, false);
viewHolder = new ViewHolder();
viewHolder.ly = (RelativeLayout) convertView
.findViewById(R.id.lyContactListItem);
viewHolder.txtName = (TextView) convertView
.findViewById(R.id.txtName);
viewHolder.txtNumber = (TextView) convertView
.findViewById(R.id.txtNumber);
viewHolder.cbxStatus = (CheckBox) convertView
.findViewById(R.id.cbxStatus);
convertView.setTag(viewHolder);
viewHolder.cbxStatus.setTag(index);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.cbxStatus.setOnCheckedChangeListener(this);
viewHolder.cbxStatus.setChecked(mData.get(position).getCheckStatus());
viewHolder.txtName.setText(mData.get(index).getName());
viewHolder.txtNumber.setText(mData.get(index).getNumber());
return convertView;
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int index = (int) buttonView.getTag();
if (isChecked)
mData.get(index).setCheckStatus(true);
else
mData.get(index).setCheckStatus(false);
}
private class ViewHolder {
RelativeLayout ly;
TextView txtName;
TextView txtNumber;
CheckBox cbxStatus;
}
}
Very simple, and don't forget one thing: The checkbox listener method should be added before the code that initializes the Checkbox status!
Conclusion:
>
Well, this section has explained a classic issue with ListView, the checkbox misalignment problem, and how to solve it by simply adding a value to record the checkbox selection status and rewriting the checkbox click event with a check. Thank you!
-1.0 Android Basic Beginner Tutorial
-1.0.1 2015 Latest Android Basic Beginner Tutorial Contents
-1.1 Background and System Architecture Analysis
-1.2 Development Environment Setup
-1.2.1 Using Eclipse + ADT + SDK to Develop Android Apps
-1.2.2 Using Android Studio to Develop Android Apps
-1.3 Solving SDK Update Issues
-1.4 Genymotion Emulator Installation
-1.5.1 Git Tutorial for Basic Local Repository Operations
-1.5.2 Git: Setting Up a Remote Repository on GitHub
-1.6 How to Play with the 9-Patch Image
-1.7 Interface Prototype Design
2.4.8 Solving the ListView Checkbox Misalignment Issue
2.5.4 Basic Usage of AutoCompleteTextView (Auto-Complete Text Box)
2.5.8 Detailed Explanation of Notification (Status Bar Notification)
2.6.4 Simple Usage of DrawerLayout (Official Side Sliding Menu)
3.6 Responding to System Setting Events (Configuration Class)
5.2.1 Fragment Example Walkthrough – Bottom Navigation Bar Implementation (Method 1)
5.2.2 Fragment Example Walkthrough – Bottom Navigation Bar Implementation (Method 2)
5.2.3 Fragment Example Walkthrough – Bottom Navigation Bar Implementation (Method 3)
5.2.4 Fragment Example Walkthrough – Bottom Navigation Bar + ViewPager for Swiping Between Pages
5.2.5 Fragment Example Walkthrough – Simple Implementation of News (Shopping) App List Fragment
6.2 Data Storage and Access – Saving User Preferences with SharedPreferences
6.3.1 Data Storage and Access – Introduction to SQLite Database
6.3.2 Data Storage and Access – Deeper Look into SQLite Database
7.1.1 What Android Network Programming Entails and Learning HTTP Protocol
7.1.2 Learning Android HTTP Request Headers and Response Headers
- 7.2.2 Android JSON Data Parsing
- 7.3.1 Android File Upload
- 7.3.2 Android File Download (1)
- 7.3.3 Android File Download (2)
- 7.4 Android Calling WebService
- 7.5.1 WebView Basic Usage
- 7.5.2 WebView and JavaScript Interaction Basics
- 7.5.3 WebView Considerations After Android 4.4
- 7.5.4 WebView File Download
- 7.5.5 WebView Cache Issues
- 7.5.6 WebView Handling Webpage Error Code Information
- 7.6.1 Socket Learning Network Basics Preparation
- 7.6.2 Socket Communication Based on TCP Protocol (1)
- 7.6.3 Socket Communication Based on TCP Protocol (2)
- 7.6.4 Socket Communication Based on UDP Protocol
- 8.1.1 Summary of 13 Drawable Types in Android Part 1
- 8.1.2 Summary of 13 Drawable Types in Android Part 2
- 8.1.3 Summary of 13 Drawable Types in Android Part 3
- 8.2.1 Bitmap Comprehensive Analysis Part 1
- 8.2.2 Bitmap-induced OOM Issues
- 8.3.1 Detailed Explanation of Three Drawing Tools
- 8.3.2 Drawing Class Practical Examples
- 8.3.3 Paint API — MaskFilter (Mask)
- 8.3.4 Paint API — Xfermode and PorterDuff Detailed Explanation (Part 1)
- 8.3.5 Paint API — Xfermode and PorterDuff Detailed Explanation (Part 2)
- 8.3.6 Paint API — Xfermode and PorterDuff Detailed Explanation (Part 3)
- 8.3.7 Paint API — Xfermode and PorterDuff Detailed Explanation (Part 4)
- 8.3.8 Paint API — Xfermode and PorterDuff Detailed Explanation (Part 5)
- 8.3.9 Paint API — ColorFilter (Color Filter) (1/3)
- 8.3.10 Paint API — ColorFilter (Color Filter) (2/3)
- 8.3.11 Paint API — ColorFilter (Color Filter) (3/3)
- 8.3.12 Paint API — PathEffect (Path Effect)
- 8.3.13 Paint API — Shader (Image Rendering)
- 8.3.14 Paint Enum/Constant Values and ShadowLayer Shadow Effect
- 8.3.15 Paint API — Typeface (Font Style)
- 8.3.16 Canvas API Detailed Explanation (Part 1)
- 8.3.17 Canvas API Detailed Explanation (Part 2) Clipping Methods Collection
- 8.3.18 Canvas API Detailed Explanation (Part 3) Matrix and drawBitmapMesh
- 8.4.1 Android Animation Collection — Frame Animation
- 8.4.2 Android Animation Collection — Tween Animation
- 8.4.3 Android Animation Collection — Property Animation — First Encounter
- 8.4.4 Android Animation Collection — Property Animation — Another Encounter
- 9.1 Using SoundPool to Play Sound Effects (Duang~)
- 9.2 MediaPlayer Playing Audio and Video
- 9.3 Using Camera to Take Photos
- 9.4 Using MediaRecord to Record Audio
- 10.1 TelephonyManager (Phone Manager)
- 10.2 SmsManager (SMS Manager)
- 10.3 AudioManager (Audio Manager)
- 10.4 Vibrator (Vibrator)
- 10.5 AlarmManager (Alarm Service)
- 10.6 PowerManager (Power Service)
- 10.7 WindowManager (Window Management Service)
- 10.8 LayoutInflater (Layout Service)
- 10.9 WallpaperManager (Wallpaper Manager)
- 10.10 Sensor Topics (1) — Introduction
- 10.11 Sensor Topics (2) — Orientation Sensor
- 10.12 Sensor Topics (3) — Accelerometer/Gyroscope Sensor
- 10.12 Sensor Topics (4) — Understanding Other Sensors
- 10.14 Android GPS Introduction
- 11.0 The 2015 Latest Android Basic Beginner's Tutorial — Completion Celebration
- 12.1 Android Practice: DrySister Viewing Girls App (First Edition) — Project Setup and Simple Implementation
- 12.2 DrySister Viewing Girls App (First Edition) — 2. Parsing Backend Data
- 12.3 DrySister Viewing Girls App (First Edition) — 3. Image Loading Optimization (Writing a Small Image Cache Framework)
- 12.4 DrySister Viewing Girls App (First Edition) — 4. Adding Data Caching (Introducing SQLite)
- 12.5 DrySister Viewing Girls App (First Edition) — 5. Code Review, Adjustment, and Logging Class Writing
- 12.6 DrySister Viewing Girls App (First Edition) — 6. Icon Creation, Obfuscation, Signing, APK Slimming, App Release