About nested ListView EditText, focus and other issues click

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/One_Month/article/details/80584473

Before this project done similar UI, it is also very cumbersome process, the desired effect is
1.EditText click there input, the cursor appears in the final results shown in Figure
2. When you finish editing the contents, put away the keyboard save the change.

Here we will use several classes
1. Custom Adapter (primary treatment also here)
2. custom EditText (processing close the input method)
3. find online monitor input method to close and open SoftKeyboardStateHelper

Write pictures described here

Item of the ListView XML file

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="#ffffff"
    android:id="@+id/my_layout">
    <com.example.listandeditfocus.MyEditText
        android:id="@+id/edit"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="张三"
        android:gravity="center"
        android:paddingTop="10dp"
        android:paddingBottom="10dp"
        android:background="@null"
       />

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="好的"
        app:layout_constraintStart_toEndOf="@id/edit"
        android:gravity="center"
        app:layout_constraintTop_toTopOf="@id/edit"/>
</android.support.constraint.ConstraintLayout>

Used here is a custom EditText, in fact, is to rewrite a way to deal with close input method, will be introduced later, EditText nested ListView, there will be a few problems
1.EditText cursor display is not normal
2.EditText focus disappear
3. ListView cause of setOnItemClickListener method set Listenner invalid, that did not respond to clicks Item,

The following code in a class to the borrow input keyboard to monitor the opening and away, where first introduced
SoftKeyboardStateHelper, from the origin of the class source class , as follows

public class SoftKeyboardStateHelper implements ViewTreeObserver.OnGlobalLayoutListener {

    public interface SoftKeyboardStateListener {
        void onSoftKeyboardOpened(int keyboardHeightInPx);
        void onSoftKeyboardClosed();
    }

    private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();
    private final View activityRootView;
    private int        lastSoftKeyboardHeightInPx;
    private boolean    isSoftKeyboardOpened;

    public SoftKeyboardStateHelper(View activityRootView) {
        this(activityRootView, false);
    }

    public SoftKeyboardStateHelper(View activityRootView, boolean isSoftKeyboardOpened) {
        this.activityRootView     = activityRootView;
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    public void onGlobalLayout() {
        final Rect r = new Rect();
        //r will be populated with the coordinates of your view that area still visible.
        activityRootView.getWindowVisibleDisplayFrame(r);

        final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
        if (!isSoftKeyboardOpened && heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
            isSoftKeyboardOpened = true;
            notifyOnSoftKeyboardOpened(heightDiff);
        } else if (isSoftKeyboardOpened && heightDiff < 200) {  //这个200是我做的一个修改,实际使用的时候debug发现有时候高度不一定是小于100 我的是189,具体情况具体修改
            isSoftKeyboardOpened = false;
            notifyOnSoftKeyboardClosed();
        }
    }

    public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;
    }

    public boolean isSoftKeyboardOpened() {
        return isSoftKeyboardOpened;
    }

    /**
     * Default value is zero (0)
     * @return last saved keyboard height in px
     */
    public int getLastSoftKeyboardHeightInPx() {
        return lastSoftKeyboardHeightInPx;
    }

    public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
        listeners.add(listener);
    }

    public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
        listeners.remove(listener);
    }

    private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {
        this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;

        for (SoftKeyboardStateListener listener : listeners) {
            if (listener != null) {
                listener.onSoftKeyboardOpened(keyboardHeightInPx);
            }
        }
    }

    private void notifyOnSoftKeyboardClosed() {
        for (SoftKeyboardStateListener listener : listeners) {
            if (listener != null) {
                listener.onSoftKeyboardClosed();
            }
        }
    }
}

Next look at the processing of the Adapter ListView

public class ListItemAdapter extends BaseAdapter implements SoftKeyboardStateHelper.SoftKeyboardStateListener {
    List<Integer> data = null;
    Context mContext = null;
    private String s;
    boolean isKeyboardOpen = false;
    int currentFocusPosition = -1;
    EditText onFocusEdit = null;

    public ListItemAdapter(List<Integer> data, Context context) {
        this.data = data;
        mContext = context;
    }

    @Override
    public int getCount() {
        return this.data.size();
    }

    @Override
    public Integer getItem(int position) {
        return this.data.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = View.inflate(mContext, R.layout.item_layout, null);
            holder.editText = convertView.findViewById(R.id.edit);
            holder.layout = convertView.findViewById(R.id.my_layout);
            holder.textView = convertView.findViewById(R.id.tv);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

		/**
			通过给Item的布局文件的最外层的ViewGroup添加OnCLick,来响应Item的点击(解决问题3 ListView的setOnItemClickListener不响应的问题,具体为什么不响应可以看下面的链接)
*/
        holder.layout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mContext.startActivity(new Intent(mContext,Main2Activity.class));
            }
        });

        final ViewHolder finalHolder = holder;
        /**
			给EditText设置FocusChangeListener,监听焦点变化,获取焦点的时候,将游标设置到最后方便删除修改
*/
        holder.editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    finalHolder.editText.setSelection(finalHolder.editText.getText().length());
                    //保存当前获取到焦点的位置和控件对象
                    currentFocusPosition = position;
                    onFocusEdit = finalHolder.editText;
                } else {
					/**
					失去焦点的时候保存当前的修改内容
*/
                    finalHolder.editText.setText(finalHolder.editText.getText());
                }
            }
        });

/**
	这一步用来处理问题2,焦点消失,点击EditText后获取到焦点,
	输入法打开,焦点又立刻消失,这是因为输入法键盘打开会是布局发生变化,会造成重新调用Adapter的getView方法,
	使EditText的焦点消失,这里我们利用一个变量currentFocusPosition记录获取到焦点的控件所处的位置,
	初始值设置为-1,表示当前没有获得焦点的控件
	(在上方的focusChange中记录),判断位置相等,重新请求获得焦点。
	!!! 注意这里不能用记录的获取焦点的控件,即onFocusEdit来做比较,因为这里的View存在复用,
	这个EditText可能获取的是上一个EditText的焦点
*/
        if (currentFocusPosition == position) {
            holder.editText.requestFocus();
        }
        return convertView;
    }

/**
	下面2个回调方法就是实现了上面的SoftKeyboardStateHelper.SoftKeyboardStateListener接口,获取到键盘打开和关闭提醒(SoftKeyboardStateHelper在Activity中通过
	 SoftKeyboardStateHelper softKeyboardStateHelper = 
	 new SoftKeyboardStateHelper(findViewById(R.id.main_layout));(Activity的布局的最外层ViewGroup)
        softKeyboardStateHelper.addSoftKeyboardStateListener(adapter);)设置
*/
    @Override
    public void onSoftKeyboardOpened(int keyboardHeightInPx) {
        isKeyboardOpen = true;

    }

    @Override
    public void onSoftKeyboardClosed() {
        isKeyboardOpen = false;
        currentFocusPosition = -1;
        //当我们收到输入法键盘关闭的时候,清除当前的EditText获取到的焦点
        if (onFocusEdit != null) {
            onFocusEdit.clearFocus();
        }
    }

    class ViewHolder {
        EditText editText;
        ConstraintLayout layout;
        TextView textView;
    }

Why not OnItemClick analysis and response to the outer layer is located OnCLick item can solve the problem of response

Next is a process of closing an input method, the treatment is carried out in a custom EditText

public class MyEditText extends android.support.v7.widget.AppCompatEditText {
    public MyEditText(Context context) {
        super(context);
    }

    public MyEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
	    //有的键盘有收起按键,有的没有,所以这里是利用手机的后退键关闭键盘
	    //判断当前点击的是后退,手指抬起,而且!! 当前EditText是有焦点的,关闭输入法,否则按照原处理方式进行
	    //EditText没有焦点 很有可能键盘已经收起了,就不需要再次关闭键盘。这时候之前设置的键盘变化监听就会回调
	    //清除当前焦点
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP && this.isFocused()) {
            InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(this.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
            return true;
        } else
            return super.onKeyPreIme(keyCode, event);
    }
}

All processing is completed, if you have a better, more concise and efficient way to share and welcome message. Improve the handling together

Guess you like

Origin blog.csdn.net/One_Month/article/details/80584473
Recommended