The difference between the custom listView radio function android:focusable and android:focusableInTouchMode

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.



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324374993&siteId=291194637