In the last article, I talked about ListView multiple selection. Here I will talk about ListView single selection:
Only one item in the listview can be selected at a time.
.XML
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:gravity="center_vertical" android:descendantFocusability="blocksDescendants" android:orientation="horizontal" android:padding="11dp"> <CheckBox android:id="@+id/custser_check" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginRight="11dp" android:background="@drawable/check_orange" android:button="@null" /> <TextView android:id="@+id/custser_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="11dp" android:layout_weight="1" android:drawableLeft="@mipmap/user" android:drawablePadding="11dp" android:gravity="center_vertical" android:text="18296127347" android:textColor="@color/black" android:textSize="18sp" /> </RelativeLayout>
.java
public class AuthorizeActivity extends BaseActivity implements View.OnClickListener { private ListView lv; private List<String> listStr; private Myadapter adapter; private String tag = "AuthorizeActivity"; private int selectPosition = -1;//The variable used to record the user's choice private String choice; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate (savedInstanceState); baseapp.TemaddActivity(this); setContentView(R.layout.activity_authorize); initView(); } private void initView() { lv = (ListView) findViewById(R.id.authorize_lv); findViewById(R.id.authorize_tv).setOnClickListener(this); findViewById(R.id.authorize).setOnClickListener(this); findViewById(R.id.authorize_next).setOnClickListener(this); listStr = new ArrayList<>(); lv.setOnItemClickListener(itemlistener); } /*item monitor*/// Block child control focus AdapterView.OnItemClickListener itemlistener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //Get the selected parameter selectPosition = position; adapter.notifyDataSetChanged(); choice = listStr.get(position); ToastUtil.showLong("The user you choose is: " + choice); } }; @Override protected void onResume() { super.onResume(); Bundle extras = getIntent().getExtras(); if (extras != null) { selectPosition = 0; String[] arrays = extras.getStringArray(CustSerAddActivity.list); listStr = Arrays.asList(arrays); choice = listStr.get(selectPosition); Logs.v(tag + "49 added data" + Arrays.toString(arrays)); initLv (lv, listStr); } } /*Initialize listView*/ private void initLv(ListView lv, List<String> list) { adapter = (Myadapter) lv.getAdapter(); if (adapter == null) { adapter = new Myadapter(this, list); lv.setAdapter(adapter); } else { adapter.setData(list); adapter.notifyDataSetChanged(); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.authorize: baseapp.TemfinishActivity(this); break; case R.id.authorize_tv: Bundle bundle = new Bundle(); bundle.putString(CustSerAddActivity.titlestr, "Add After Sales Personnel"); bundle.putString(CustSerAddActivity.activity, "AuthorizeActivity"); bundle.putStringArray(CustSerAddActivity.list, listStr.toArray(new String[listStr.size()])); Logs.v(tag + " 110 " + listStr.size()); SmallUtil.getActivity(AuthorizeActivity.this, CustSerAddActivity.class, bundle); baseapp.TemfinishActivity(this); break; case R.id.authorize_next: Intent a = new Intent(AuthorizeActivity.this, AuthorizeChoiceActivity.class); a.putExtra(AuthorizeChoiceActivity.UserStr, choice); startActivity(a); break; } } /*Custom Authorized Adapter*/ private class Myadapter extends BaseAdapter { private Context context; private List<String> brandsList; public Myadapter(Context context, List<String> brandsList) { this.context = context; this.brandsList = brandsList; } @Override public int getCount() { return listStr.size(); } @Override public Object getItem(int position) { return listStr.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(context).inflate( R.layout.item_authorizecheck, null); } TextView name = ViewHolderUtil.get(convertView, R.id.custser_name); name.setText(brandsList.get(position)); CheckBox checkBox = ViewHolderUtil.get(convertView, R.id.custser_check); if (position == selectPosition) { checkBox.setChecked(true); } else { checkBox.setChecked(false); } return convertView; } public void setData(List<String> scanResults) { brandsList = scanResults; } } }
Focus: The parent control seizes the focus problem
Sometimes, when each item in the ListView is a custom View, the listener of the ListView's OnItemClickListener may not be called. Please see the following:
Possible reason one:
If there is a Button or Checkable subclass control in your custom ListViewItem, then the default focus is given to the sub-control, and the basis for the ListView's Item to be selected is that it can obtain the Focus, that is to say, we can pass the ListView The focusable property of all the controls contained in the Item is set to false, so that the Item of the ListView automatically obtains the permission of Focus and can be selected.
We can set the android:descendantFocusability="blocksDescendants" to the root control of the Item Layout, so that the Item Layout blocks all child controls from obtaining the Focus permission, and there is no need to reset the focusable attribute for each control in the Item Layout. , so that you can successfully respond to the onItemClick() method in onItemClickListener.
Summary of reasons:
The View inside the Item in the ListView gets the focus, such as Button, Checkbox, etc.
Solution:
Don't let the View inside the Item in the ListView get the focus, just do this: android:descendantFocusability="blocksDescendants"
Constant | Value | Description |
beforeDescendants | 0 | The ViewGroup will get focus before any of its descendants. |
afterDescendants | 1 | The ViewGroup will get focus only if none of its descendants want it. |
blocksDescendants | 2 | The ViewGroup will block its descendants from receiving focus. |
This property defines the relationship between the viewGroup and its child controls when a view gains focus.
There are three types of property values:
beforeDescendants: viewgroup will give priority to its subclass controls and get the focus
afterDescendants: viewgroup gets focus only when its subclass controls don't need to get focus
blocksDescendants: viewgroup will override the subclass control and get the focus directly
Effect picture:
found a bug
checkbox light write
android:focusable="false"
If the properties checked by the checkBox cannot be blocked, it will still grab the focus of its parent control item, causing the onItemClickListener to not work.
It should be written as follows:
android:clickable:好像是控制按钮是否可以被点击和点击之后触发监听器事件。
android:focusable:控制键盘是否可以获得这个按钮的焦点。(我按实体键盘上方向键,button被选中)
The difference between android:focusable and android:focusableInTouchMode
The former is for the case of operating under the keyboard. If it is set to true, the keyboard will be selected up and down, left and right, and the focus will move accordingly.
The latter is obviously for the case of touch screen, that is, when we click on a control on the screen, we do not immediately execute the corresponding click logic, but first display the focus (that is, the control is selected), and then click to execute the logic .
android:focusable="true" will not change the android:focusableInTouchMode, so the focus is only displayed in the keyboard state, and the focus still cannot be displayed in the TouchMode state.
android:focusable="false", will make android:focusableInTouchMode="false".
relatively
android:focusableInTouchMode="false", will not affect android:focusable.
android:focusableInTouchMode="true", must be android:focusable="true"
It's a bit convoluted to say.
But keep in mind that for mobile phones in the current touch screen era, if we want to get the focus, we only need to set
android:foucusableInTouchMode="true" is fine.
All getting the focus, there must be a premise, that is, the control must be set android:clickable=”true”, if it can’t be clicked, it should be meaningless to set the focus.