1. 程式人生 > >關於ListView中巢狀EditText,焦點及其他點選問題

關於ListView中巢狀EditText,焦點及其他點選問題

之前專案做過這個類似的UI,處理起來也很麻煩,要求的效果是
1.EditText點擊出現輸入法,遊標顯示在最後,效果如圖
2.編輯完內容後,收起鍵盤儲存修改內容。

這裡會用到幾個類
1.自定義Adapter(主要的處理也是在這裡)
2.自定義的EditText(處理關閉輸入法)
3.網上找的監聽輸入法關閉和開啟SoftKeyboardStateHelper

這裡寫圖片描述

ListView的Item的XML檔案

<?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>

這裡用到的是自定義的EditText,其實就是重寫了一個方法,去處理關閉輸入法,後面會介紹,EditText巢狀在ListView中,會出現幾個問題
1.EditText遊標顯示不正常
2.EditText焦點消失
3.造成ListView的setOnItemClickListener方法設定的Listenner無效,即點選Item卻沒有響應,

下面的程式碼中會借用到一個類來監聽輸入法鍵盤的開啟和收起,這裡先介紹下
SoftKeyboardStateHelper,這個類的出處來自該類的來源地,程式碼如下

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();
            }
        }
    }
}

接著看下在ListView的Adapter中進行的處理

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;
    }

接下來是處理關閉輸入法,這個處理是在自定義的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);
    }
}

所有處理已完成,如果大家有更好的,更簡潔高效的方法,歡迎分享和留言。一起改進處理方式

相關推薦

關於ListViewEditText焦點及其問題

之前專案做過這個類似的UI,處理起來也很麻煩,要求的效果是 1.EditText點擊出現輸入法,遊標顯示在最後,效果如圖 2.編輯完內容後,收起鍵盤儲存修改內容。 這裡會用到幾個類 1.自定義Adapter(主要的處理也是在這裡) 2.自定義的EditText(

ListViewViewFlowViewFlow滑動有些卡頓的問題~

最近做類似於網易新聞頭條那種圖片Banner,實現方法是:在ListView中巢狀ViewFlow,但是ViewFlow的滑動總是不是那麼順暢,覺得應該是觸屏事件攔截衝突的問題吧,在網上查閱了一下我的解決方法如下: 在ViewFlow中宣告mListView,然後將父ListView傳入到ViewFlow,

android ScrollViewGridViewListView只顯示一行的解決辦法

注:本文是由網上大神分享的解決方案彙集而成 方法一: 重寫ListView、GridView: 重寫ListView: public class MyListView extends ListView { public MyListView(Context contex

ListViewGridView時GridView的資料無法完全顯示只顯示一行

這種情況下需要自定義一個GridView,然後重寫GridView的onMeasure(int widthMeasureSpec, int heightMeasureSpec)的方法,將GridView重新測量,並且指定GridView的新的高度 package com.y

ScrollViewEditText導致EditText顯示多行時滑動失效的問題

ScrollView巢狀EditText,這會有什麼問題呢,我這裡說的是當EditText內輸入多行內容,當EditText所在佈局不夠的時候,必然需要滑動檢視輸入的所有內容。可是當我們把EditText放在ScrollView裡面的時候,會發現EditText的滑動失效了。 原因就

陣列物件根據物件的某個字對物件進行去重

// 陣列中巢狀物件,根據物件的某個欄位進行物件去重 function uniqObj(data, name) { var dataArr = []; var dataObj = {}; for (var i = 0; i < data.length; i+

fragmentviewpagervierpager有多個fragment不顯示 ...

現在好多應用流行一種佈局。底部幾個工具欄選項,上面也有類似tab的選項。 底部用RadioGroup控制fragment的切換。以上有五個fragment。 第一個fragment,代表著首頁。首頁又是一個類似tab的fragment,使用viewpager切換著兩

在Popupwindow佈局ScrollView滑動內容時檢視出現反覆閃爍的問題

解決辦法: 將顯示PopupWindow的方法由showAsDropDown()改為showAtLocation() 程式碼如下 private PopupWindow popupWind

fragmentviewpagerviewpager有多個fragment裡面fragment沒有顯示

fragment巢狀fragment導致裡面fragment介面沒有顯示,例子如下: private void InitViewPager(View parentView) { mPag

在FragmentWebview第一次開啟閃屏問題

在Fragment中巢狀Webview,特別是對Activity開啟了硬體加速,在第一次開啟時會出現閃屏,或者出現下桌面後就恢復正常,第二次就不會出現。 對於這種情況很簡單,在存放Fragment的Activity中加入一行程式碼即可解決: getWindow().se

listviewviewpager的實現總結

最近在做一個專案需要在listView中巢狀viewPager作為第一項,效果如下: 上面的佈局就是一個listView,在實現過程中遇到了以下問題: 1.listView中第一項為viewPager,其他項為單獨包含兩種資料型別,導致listView佈局混亂。 2.v

fragmentviewpagervierpager有多個fragment不顯示而且滑動卡頓

現在好多應用流行一種佈局。底部幾個工具欄選項,上面也有類似tab的選項。 底部用RadioGroup控制fragment的切換。以上有五個fragment。 第一個fragment,代表著首頁。首頁又是一個類似tab的fragment,使用viewpager切換著兩個fragment。  priv

Android在RecyclerViewScrollView解決兩者間的滑動衝突

在RecyclerView中的item中巢狀一些佈局如TextView,在這種情況下如TextView的字數很多超過所設定的佈局大小。 這樣就需要在item中加一個ScrollView可以用於使用者的滑動。 1.RecyclerView的item佈局如: <?xml

androidListViewGridView並且把GridView當中的內容全部顯示出來的方法

程式碼如下所示: public class MyGridView extends GridView { public MyGridView(android.content.Context context, android.u

Android-ListView(ListView)控制元件時item的事件不起作用的問題

解決:1、在主listview佈局檔案中的listview中新增屬性 android:focusable="false"              2、在子listview中最頂上的佈局檔案新增屬性

ListviewCheckbox的簡單解決辦法

最近專案中做了一個關於批量刪除的這樣一個操作,以前是會做的,誰知道記性不好忘光了,經過一番折騰還是完美的實現了,相信後面還有無數個和我一樣的渣渣會遇到這個問題,那麼就讓我來分享一下咯。 當然這個checkbox控制元件是寫在item佈局中的。我這邊的需求是點選編輯按鈕才會顯

ListViewGridView事件

做一個專案時,需要在ListView中巢狀GridView,因為ListView的每個條目中不一定出現GridView,那麼問題來了,新增GridView的Item的點選事件後,有GridView出現的條目中,ListView的Item點選事件無法觸發,這時我們就需要設定L

recyclerviewGridView去遮蔽後者的事件而是前者響應到事件。

無論是標題中的巢狀方式,還是其它列表控制元件之間的巢狀,都適用。 1、在GirdView的所在佈局的根佈局中設定改屬性: android:descendantFocusability="blacksDescendants"  2、動態設定GirdView的如下屬性:   gridvi

ListViewItem與Item的子控制元件事件衝突問題解決

心靈包含人所有的一切有意識、無意識的思想、情感和行為。——《星夜心理書系》 1、問題 在Android開發時,ListView中點選一個Item,會一併觸發其子控制元件的點選事件。比如Item中的Button、ImageButton等。導致了點選

ListView嵌入佈局的Button或多個事件

ListView中嵌入佈局的多個點選事件 有時候在ListView嵌入的佈局中有多個事件需要點選,比如一個item中有TextView和Button兩個佈局,當我們需要獲取這兩個點選事件時,我們應該如何去獲取呢,通常來說,我們都是已經固定好了TextVie