Android Custom Keyboard 예제


2개의 EditText가 있을때, 

첫번째 EditText 선택시는 OEM Keyboard 를 사용하여 입력하고,

두번째 EditText 선택시는 숫자만으로 이루어진 Custom Keyboard를 사용하여 입력한다.



  





1. CustomNumpadActivity.java


public class CustomNumpadActivity extends Activity {
    /** Called when the activity is first created. */
	CustomNumpadView cnv =  null;
	Boolean mViewKeyboard = true;
	Button btn_hide = null;
	Context mContext = null;
	EditText editTextOEM, editTextCustom = null;
	InputMethodManager imm = null;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mContext = this;
        imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
        
        editTextOEM = (EditText) findViewById(R.id.editTextOEM);
        editTextOEM.setOnTouchListener(mTouchListener);
        editTextCustom = (EditText) findViewById(R.id.editTextCustom);
        editTextCustom.setInputType(InputType.TYPE_NULL);
        editTextCustom.setOnTouchListener(mTouchListener);
        
        //Get Numpad to set current activity to dispatch key events
        cnv = (CustomNumpadView) findViewById(R.id.numpadView);
        cnv.setActionListenerActivity(this);
        System.out.println("Came here successfully");
        
        btn_hide = (Button) findViewById(R.id.btn_hide);
        btn_hide.setOnClickListener(mClickListener);
        
        goneCustomKeyboard();
    }
        
    private void goneCustomKeyboard(){ // 키보드 숨기기
		cnv.setVisibility(View.GONE);
		mViewKeyboard = false;
		btn_hide.setText("Custom 키보드 보이기");
    }
    private void visibleCustomKeyboard(){ // 키보드 보이기
		cnv.setActionListenerActivity(CustomNumpadActivity.this);
		cnv.setVisibility(View.VISIBLE);
		mViewKeyboard = true;
		btn_hide.setText("Custom 키보드 숨기기");
    }
    
    View.OnClickListener mClickListener = new View.OnClickListener() {
		
		@Override
		public void onClick(View v) {
			switch (v.getId()) {

			case R.id.btn_hide:
			{
				if(mViewKeyboard == true){
					goneCustomKeyboard();
				}else{
					visibleCustomKeyboard();					
				}
			}
				break;
			default:
				break;
			}
			
		}
	};
	
	View.OnTouchListener mTouchListener = new View.OnTouchListener() {
		
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			switch (v.getId()) {
			case R.id.editTextCustom:	// 커스텀 키보드
				imm.hideSoftInputFromWindow(editTextCustom.getWindowToken(), 0); // 만약 OEM 키보드가 열려 있을 경우 닫음.
				visibleCustomKeyboard();
				break;
			case R.id.editTextOEM:		// OEM 키보드
				goneCustomKeyboard();
				break;
			default:
				break;
			}
			return false;
		}
	};
}


2. main.xml


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="vertical" >

    <LinearLayout 

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal">

        <TextView 

            android:layout_width="150dp"

            android:layout_height="wrap_content"

            android:text="OEM keyboard"/>

   <EditText

       android:id="@+id/editTextOEM"

       android:layout_width="match_parent"

       android:layout_height="wrap_content"

       android:ems="10" >

   </EditText>

    </LinearLayout>


    <LinearLayout 

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal">

        <TextView 

            android:layout_width="150dp"

            android:layout_height="wrap_content"

            android:text="Custom keyboard"/>

        

        <EditText

       android:id="@+id/editTextCustom"

       android:layout_width="match_parent"

       android:layout_height="wrap_content"

       android:ems="10"

       android:inputType="numberDecimal">

<!--         <requestFocus /> -->

   </EditText>        

    </LinearLayout>

    



    <Button

        android:id="@+id/btn_hide"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="Custom 키보드 숨기기" />


    <akash.app.customnumpad.CustomNumpadView

        android:id="@+id/numpadView"

        android:layout_width="250dip"

        android:layout_height="100dip" android:visibility="visible"/>


</LinearLayout>


3. CustomNumpadView.java


public class CustomNumpadView extends KeyboardView {

    CustomOnKeyboardActionListener keyListener;
    Keyboard kb = null;
    public CustomNumpadView(Context context, AttributeSet attrs) {
        super(context, attrs);
        kb = new Keyboard(context,R.xml.keyboard);
    }
    
    public void setActionListenerActivity(Activity act){
        keyListener = new CustomOnKeyboardActionListener(act);
        this.setOnKeyboardActionListener(keyListener);
        this.setKeyboard(kb);
    }
    
    @Override
    public boolean isInEditMode() {
        return true;
    };
    
    private class CustomOnKeyboardActionListener implements OnKeyboardActionListener {
        Activity owner;
        
        public CustomOnKeyboardActionListener(Activity activity){
            owner = activity;
        }
        
        @Override
        public void onKey(int primaryCode, int[] keyCodes) {
            long eventTime = System.currentTimeMillis();
            KeyEvent event = new KeyEvent(eventTime, eventTime,
                    KeyEvent.ACTION_DOWN, primaryCode, 0, 0, 0, 0,
                    KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
            owner.dispatchKeyEvent(event);
        }

        @Override
        public void onPress(int primaryCode) {
        }

        @Override
        public void onRelease(int primaryCode) {
        }

        @Override
        public void onText(CharSequence text) {
        }

        @Override
        public void swipeDown() {
        }

        @Override
        public void swipeLeft() {
        }

        @Override
        public void swipeRight() {
        }

        @Override
        public void swipeUp() {
        }
        
    }

}   


4. keyboard.xml


<?xml version="1.0" encoding="utf-8"?>

<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"

    android:horizontalGap="0px"

    android:keyHeight="50dip"

    android:keyWidth="33%"

    android:verticalGap="5px" >


    <Row>

        <Key

            android:codes="8"

            android:keyEdgeFlags="left"

            android:keyLabel="1" />

        <Key

            android:codes="9"

            android:keyLabel="2" />

        <Key

            android:codes="10"

            android:keyLabel="3" />

    </Row>

    <Row>

        <Key

            android:codes="11"

            android:keyEdgeFlags="left"

            android:keyLabel="4" />

        <Key

            android:codes="12"

            android:keyLabel="5" />

        <Key

            android:codes="13"

            android:keyEdgeFlags="right"

            android:keyLabel="6" />

    </Row>

    <Row>

        <Key

            android:codes="14"

            android:keyEdgeFlags="left"

            android:keyLabel="7" />

        <Key

            android:codes="15"

            android:keyLabel="8" />

        <Key

            android:codes="16"

            android:keyEdgeFlags="right"

            android:keyLabel="9" />

    </Row>

    <Row>

        <Key

            android:codes="67"

            android:iconPreview="@drawable/ic_key_delete"

            android:keyEdgeFlags="left"

            android:keyIcon="@drawable/ic_key_delete" />

        <Key

            android:codes="7"

            android:keyLabel="0" />

        <Key

            android:codes="56"

            android:keyLabel="." />

    </Row>


</Keyboard>


5. AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="akash.app.customnumpad"

    android:versionCode="1"

    android:versionName="1.0" >


    <uses-sdk android:minSdkVersion="15" />


    <application

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name" >

        <activity

            android:name=".CustomNumpadActivity"

            android:label="@string/app_name"

            android:windowSoftInputMode="stateAlwaysHidden|adjustPan" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />


                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>


</manifest>



아래 원본에 있는것을 좀 수정해봄.

원본 : https://github.com/gaara87/Android-CustomNumpad


포스팅된 프로젝트 파일 : 

Android-CustomNumpad-master.zip



위 프로젝트의 단점은 Custom Keyboard 사용시 커서가 없다는것..

커서가 있는것은 아래 링크 참조. (프로젝트 소스도 있음. 커서와 백스페이스 처리도 되어 있음.  좋음.)

http://www.fampennings.nl/maarten/android/09keyboard/index.htm


1. MainActivity.java


public class MainActivity extends Activity {

    CustomKeyboard mCustomKeyboard;
    
    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        mCustomKeyboard= new CustomKeyboard(this, R.id.keyboardview, R.xml.hexkbd );
        
        mCustomKeyboard.registerEditText(R.id.edittext0); 
        //mCustomKeyboard.registerEditText(R.id.edittext1);
        //mCustomKeyboard.registerEditText(R.id.edittext2);
        mCustomKeyboard.registerEditText(R.id.edittext3);
        mCustomKeyboard.registerEditText(R.id.edittext4);
    }
    
    @Override public void onBackPressed() { 
    	// NOTE Trap the back key: when the CustomKeyboard is still visible hide it, only when it is invisible, finish activity 
        if( mCustomKeyboard.isCustomKeyboardVisible() ) mCustomKeyboard.hideCustomKeyboard(); else this.finish();
    }

}



2. CustomKeyboard.java


class CustomKeyboard {

    /** A link to the KeyboardView that is used to render this CustomKeyboard. */
    private KeyboardView mKeyboardView;
    /** A link to the activity that hosts the {@link #mKeyboardView}. */
    private Activity     mHostActivity;

    /** The key (code) handler. */
    private OnKeyboardActionListener mOnKeyboardActionListener = new OnKeyboardActionListener() {

        public final static int CodeDelete   = -5; // Keyboard.KEYCODE_DELETE
        public final static int CodeCancel   = -3; // Keyboard.KEYCODE_CANCEL
        public final static int CodePrev     = 55000;
        public final static int CodeAllLeft  = 55001;
        public final static int CodeLeft     = 55002;
        public final static int CodeRight    = 55003;
        public final static int CodeAllRight = 55004;
        public final static int CodeNext     = 55005;
        public final static int CodeClear    = 55006;

        @Override public void onKey(int primaryCode, int[] keyCodes) {
            // NOTE We can say '' in the xml file; all codes come in keyCodes, the first in this list in primaryCode
            // Get the EditText and its Editable
            View focusCurrent = mHostActivity.getWindow().getCurrentFocus();
            if( focusCurrent==null || focusCurrent.getClass()!=EditText.class ) return;
            EditText edittext = (EditText) focusCurrent;
            Editable editable = edittext.getText();
            int start = edittext.getSelectionStart();
            // Apply the key to the edittext
            if( primaryCode==CodeCancel ) {
                hideCustomKeyboard();
            } else if( primaryCode==CodeDelete ) {
                if( editable!=null && start>0 ) editable.delete(start - 1, start);
            } else if( primaryCode==CodeClear ) {
                if( editable!=null ) editable.clear();
            } else if( primaryCode==CodeLeft ) {
                if( start>0 ) edittext.setSelection(start - 1);
            } else if( primaryCode==CodeRight ) {
                if (start < edittext.length()) edittext.setSelection(start + 1);
            } else if( primaryCode==CodeAllLeft ) {
                edittext.setSelection(0);
            } else if( primaryCode==CodeAllRight ) {
                edittext.setSelection(edittext.length());
            } else if( primaryCode==CodePrev ) {
                View focusNew= edittext.focusSearch(View.FOCUS_BACKWARD);
                if( focusNew!=null ) focusNew.requestFocus();
            } else if( primaryCode==CodeNext ) {
                View focusNew= edittext.focusSearch(View.FOCUS_FORWARD);
                if( focusNew!=null ) focusNew.requestFocus();
            } else { // insert character
                editable.insert(start, Character.toString((char) primaryCode));
            }
        }

        @Override public void onPress(int arg0) {
        }

        @Override public void onRelease(int primaryCode) {
        }

        @Override public void onText(CharSequence text) {
        }

        @Override public void swipeDown() {
        }

        @Override public void swipeLeft() {
        }

        @Override public void swipeRight() {
        }

        @Override public void swipeUp() {
        }
    };

    /**
     * Create a custom keyboard, that uses the KeyboardView (with resource id viewid) of the host activity,
     * and load the keyboard layout from xml file layoutid (see {@link Keyboard} for description).
     * Note that the host activity must have a KeyboardView in its layout (typically aligned with the bottom of the activity).
     * Note that the keyboard layout xml file may include key codes for navigation; see the constants in this class for their values.
     * Note that to enable EditText's to use this custom keyboard, call the {@link #registerEditText(int)}.
     *
     * @param host The hosting activity.
     * @param viewid The id of the KeyboardView.
     * @param layoutid The id of the xml file containing the keyboard layout.
     */
    public CustomKeyboard(Activity host, int viewid, int layoutid) {
        mHostActivity= host;
        mKeyboardView= (KeyboardView)mHostActivity.findViewById(viewid);
        mKeyboardView.setKeyboard(new Keyboard(mHostActivity, layoutid));
        mKeyboardView.setPreviewEnabled(false); // NOTE Do not show the preview balloons
        mKeyboardView.setOnKeyboardActionListener(mOnKeyboardActionListener);
        // Hide the standard keyboard initially
        mHostActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
    }

    /** Returns whether the CustomKeyboard is visible. */
    public boolean isCustomKeyboardVisible() {
        return mKeyboardView.getVisibility() == View.VISIBLE;
    }

    /** Make the CustomKeyboard visible, and hide the system keyboard for view v. */
    public void showCustomKeyboard( View v ) {
        mKeyboardView.setVisibility(View.VISIBLE);
        mKeyboardView.setEnabled(true);
        if( v!=null ) ((InputMethodManager)mHostActivity.getSystemService(Activity.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(), 0);
    }

    /** Make the CustomKeyboard invisible. */
    public void hideCustomKeyboard() {
        mKeyboardView.setVisibility(View.GONE);
        mKeyboardView.setEnabled(false);
    }

    /**
     * Register EditText with resource id resid (on the hosting activity) for using this custom keyboard.
     *
     * @param resid The resource id of the EditText that registers to the custom keyboard.
     */
    public void registerEditText(int resid) {
        // Find the EditText 'resid'
        EditText edittext= (EditText)mHostActivity.findViewById(resid);
        // Make the custom keyboard appear
        edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
            // NOTE By setting the on focus listener, we can show the custom keyboard when the edit box gets focus, but also hide it when the edit box loses focus
            @Override public void onFocusChange(View v, boolean hasFocus) {
                if( hasFocus ) showCustomKeyboard(v); else hideCustomKeyboard();
            }
        });
        edittext.setOnClickListener(new OnClickListener() {
            // NOTE By setting the on click listener, we can show the custom keyboard again, by tapping on an edit box that already had focus (but that had the keyboard hidden).
            @Override public void onClick(View v) {
                showCustomKeyboard(v);
            }
        });
        // Disable standard keyboard hard way
        // NOTE There is also an easy way: 'edittext.setInputType(InputType.TYPE_NULL)' (but you will not have a cursor, and no 'edittext.setCursorVisible(true)' doesn't work )
        edittext.setOnTouchListener(new OnTouchListener() {
            @Override public boolean onTouch(View v, MotionEvent event) {
                EditText edittext = (EditText) v;
                int inType = edittext.getInputType();       // Backup the input type
                edittext.setInputType(InputType.TYPE_NULL); // Disable standard keyboard
                edittext.onTouchEvent(event);               // Call native handler
                edittext.setInputType(inType);              // Restore input type
                return true; // Consume touch event
            }
        });
        // Disable spell check (hex strings look like words to Android)
        edittext.setInputType(edittext.getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
    }

}




+ Recent posts