[Android]讓ListView item被選擇時可以變換背景

看到標題時,一開始以為是個很簡單的問題,結果搞了我一、兩天試了n種方法,都無法解決。後來看了一些文章後,得到了一些解答,首先要明白一點,在觸碰模式下(Touch Mode)下是沒有selection state的,這是android developer blog的說明

In touch mode, there is no focus and no selection.

所以必須想一下有哪些作法,可以騙過android以達到selected的效果,想了想,可能還是要從自訂的layout來下手,果然神人vimalrajpara2006 有解答啦!就是自訂一個CheckAbleLayout來達到ListView有單選的效果,以下是我參考其原始碼修改而來

  • 首先自訂一個CheckAbleLayout
package com.example.listview.selected.row;

import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.util.AttributeSet;
import android.widget.Checkable;
import android.widget.LinearLayout;

public class CheckableLayout extends LinearLayout implements Checkable {
    private boolean mChecked;

    public CheckableLayout(Context context) {
        super(context);
    }

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

    public void setChecked(boolean checked) {
        mChecked = checked;
        
        // Use this code for setting custom color in background of this layout
        // 當item被點選後,將其背景色改為藍色
        setBackgroundDrawable(checked ? new ColorDrawable(android.graphics.Color.BLUE) : null);
        
        // Use this code for setting custom image in background of this layout
        /*setBackgroundResource(checked ? R.drawable.ic_action_search
                : R.drawable.ic_launcher);*/
    }

    public boolean isChecked() {
        return mChecked;
    }

    public void toggle() {
        setChecked(!mChecked);
    }

}

  • 再來要將ListView的choiseMode設定為singleChoise
  • 最後設定相關的listener

這樣子就大功告成啦!

範例原始檔下載

[Android]偵測軟體鍵盤是否已經隱藏

眾所皆知,android的手機五花八門,其輸入法的型態也是一樣,像Sony的手機會有這個隱藏鍵盤的圖示,紅色框框處。

image

那該如何偵測鍵盤是否已經按下了隱藏鍵盤圖示呢?找了一些論譠和資源,發現並沒有提供,唯一的線索就是顯示軟體鍵盤時,整理的View的配置會有改變,看來是得從這邊下手了。

做法很簡單,只要Activity或Fragment所繫結的Root view layout動個手腳就可以了。假如App的畫面是佔滿螢幕畫面的話,可以參考下列的作法。

  • 實作一個Custom View,假設Root view layout是RelativeLayout
/**
 * Input {@link RelativeLayout}
 * <p>
 * 為了能夠偵測鍵盤在顯示時,被按下隱藏鍵盤圖示(EX: sony的手機, htc sensation, etc....)後,做一些處理的自訂RelativeLayout
 * 
 * @author Jay Lee
 * 
 */
public class KeyboardAwareRelativeLayout extends RelativeLayout {
    private OnKeyboardHiddenListener mCallBack;

    /**
     * 鍵盤被隱藏的Listener
     * 
     */
    public interface OnKeyboardHiddenListener {

        /**
         * 當鍵盤被點選穩藏時要執行的動作
         */
        public void onKeyboardHidden();
    }

    private boolean mKeyboardVisible = false;

    /**
     * Construct a KeyboardAwareRelativeLayout object.
     * 
     * @param context
     *            Context
     */
    public KeyboardAwareRelativeLayout(Context context) {
        super(context);
    }

    /**
     * Construct a KeyboardAwareRelativeLayout object.
     * 
     * @param context
     *            Context
     * @param attrs
     *            AttributeSet
     */
    public KeyboardAwareRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * Construct a KeyboardAwareRelativeLayout object.
     * 
     * @param context
     *            Context
     * @param attrs
     *            AttributeSet
     * @param defStyle
     *            Default style
     */
    public KeyboardAwareRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public boolean isKeyboardVisible() {
        return mKeyboardVisible;
    }

    /**
     * 定義當隱藏鍵盤的Listener
     * 
     * @param listener
     *            OnKeyboardHiddenListener
     */
    public void setOnKeyboardHiddenListener(OnKeyboardHiddenListener listener) {
        mCallBack = listener;
    }

    private void updateKeyboardVisible() {
		// 取得此View的高度
        int viewHeight = getHeight();
		// 取得手機螢幕實際高度
        int displayHeight = getDisplayHeight();

        // 計算時,需要包含Status Bar,而Status Bar的高度為25dp
		// 需要利用程式動態計算出來
		Resources r = getResources();
        int maxStatusBarHeight = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25f, r.getDisplayMetrics()));
        
        // 當View的高度加上Status Bar的高度比螢幕小時,代表軟體鍵盤目前顯示在畫面上
        boolean oldValue = mKeyboardVisible;
        mKeyboardVisible = (viewHeight + maxStatusBarHeight < displayHeight);
        if (oldValue != mKeyboardVisible && !mKeyboardVisible && mCallBack != null) {
            mCallBack.onKeyboardHidden();
        }
    }
	
	private int getDisplayHeight() {
        WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);

        Display display = windowManager.getDefaultDisplay();

        return display.getHeight();
    }

    /**
     *  如果在onLayout時無法辨識鍵盤被關閉時,也可以透過設定mKeyboardVisible的屬性
     *  並且在mKeyboardVisible為false時,執行mCallBack的動作
     */
    public void setKeyboardVisible(boolean mKeyboardVisible) {
        this.mKeyboardVisible = mKeyboardVisible;
        if (!mKeyboardVisible && mCallBack != null ) {
            mCallBack.onKeyboardHidden();
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (!this.isInEditMode()) {
            updateKeyboardVisible();
        }
    }

}
  • 在Activity或Fragment裡面,將此View實作OnKeyboardHiddenListener
public class MyActivity extends Activity {
    // Views
    private KeyboardAwareRelativeLayout mRootLayout;
    
    // Listeners
    private KeyboardAwareRelativeLayout.OnKeyboardHiddenListener mRootLayoutOnKeyboardHiddenListener = new KeyboardAwareRelativeLayout.OnKeyboardHiddenListener() {

        @Override
        public void onKeyboardHidden() {
            // TODO 在這邊撰寫當軟體鍵盤隱藏時,要做的處理
        }
    };

    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		mRootLayout = (KeyboardAwareRelativeLayout) view.findViewById(R.id.root);
		mRootLayout.setOnKeyboardHiddenListener(mRootLayoutOnKeyboardHiddenListener);        
    } 

}
  • 最後在AndroidManifest.xml裡面的<activity>節點裡面,加入android:windowSoftInputMode=”adjustResize” 

如此一來,就能在軟體鍵盤被隱藏時來處理一些事情。

參考資源:

  1. Canned Coding
  2. http://stackoverflow.com/q/3425932/1004367

在巢狀的Preference Screen模擬按下back鍵移除Preference Screen

如果有需要透過程式碼來模擬按下back鍵來移除巢狀Preference Screen時,可以參考這個方法。

此方法主要的原則是,巢狀Preference Screen在顯示時,是以 Dialog 來顯示。以下是Android Developer的說明

When it appears inside another preference hierarchy, it is shown and serves as the gateway to another screen of preferences (either by showing another screen of preferences as a Dialog or via a startActivity(android.content.Intent) from the getIntent()). The children of this PreferenceScreen are NOT shown in the screen that this PreferenceScreen is shown in. Instead, a separate screen will be shown when this preference is clicked.

所以要移除Preference Screen的話,只要取得該Preference Screen的Dialog將其移除,就可以移除掉Preference Screen

yourPreferenceScreen.getDialog().dismiss();