카테고리 없음

[Android] ViewFlipper 활용하여 보안 키보드 만들기

너구리V 2012. 12. 11. 17:49

1. 보안키보드 ?

 

레이아웃내의 에디트 박스를 누르면 안드로이드 자체 소프트키보드가 팝업이 된다.

 

기본으로 제공되는 키보드말고 커스텀 키보드를 만들어보자.

 

우선 만들고자 하는 보안키보드는 국민은행 홈페이지 같은 금융사 웹사이트를 들어가보면 비밀번호를 누르는 곳이 자판배열이 1,2,3,...

 

이런식으로 차례대로 나오는 것이 아니라 랜덤으로 뒤섞여서 나온다.

 

2. XML 구성

 

 

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout  
 xmlns:android="
http://schemas.android.com/apk/res/android"
 android:id="@+id/relativeLayout"  
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
 <EditText 
  android:id="@+id/editText"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  
android:layout_alignParentTop="true"
  android:password="true" />
 <ViewFlipper
  android:id="@+id/viewFlipper"  
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content"
  android:layout_alignParentBottom="true" >  
  <LinearLayout 
   android:id="@+id/firstViewFlipper"
      android:orientation="vertical"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:background="#c0c0c0" >
   <TableLayout
        android:id="@+id/tableLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:stretchColumns="0,1,2"
        >
        <TableRow>
         <Button style="@style/keyboard_number"/>
         <Button style="@style/keyboard_number"/>
         <Button style="@style/keyboard_number"/>
     </TableRow>
     <TableRow>
         <Button style="@style/keyboard_number"/>
         <Button style="@style/keyboard_number"/>
         <Button style="@style/keyboard_number"/>
     </TableRow>
     <TableRow>
         <Button style="@style/keyboard_number"/>
         <Button style="@style/keyboard_number"/>
         <Button style="@style/keyboard_number"/>
     </TableRow>
     <TableRow>
         <Button android:id="@+id/key_done" android:text="확 인" style="@style/keyboard_special"/>
         <Button style="@style/keyboard_number"/>
         <Button android:id="@+id/key_backspace" android:text="←" style="@style/keyboard_special"/>
     </TableRow>
    </TableLayout>   
  </LinearLayout>
 </ViewFlipper>
 </RelativeLayout>

 

 

전체 기본 레이아웃을 RelativeLayout  로 잡고 에디트 박스를 화면의 위쪽에 (android:layout_alignParentTop="true") 붙이고,

 

키보드는 화면의 아래쪽에 (android:layout_alignParentBottom="true") 붙인다.

 

ViewFlipper 안에 LinearLayout을 위치 시키고 그안에 키보드 구성을 위한 TableLayout을 위치시킨다. (그 이유는 아래에서 다시 설명합니다.)

 

즉, 전체 레이아웃은 RelativeLayout - ViewFlipper - LinearLayout - TableLayout 이렇게 된다.

 

TableLayout에는 TableRow로 4행 3열의 테이블을 구성한다. 가장 마지막 행의 왼쪽과 오른쪽은 확인 키와 백스페이스 키이므로 id를 지정해준다.

 

(버튼의 스타일에 관한 포스팅은 http://blog.naver.com/notinoti/80114991342 을 참조!)

 

 

 

3. 자바 소스

 

 

package kr.infomax.RandomNumberKey;

import java.util.ArrayList;
import java.util.Random;

import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewFlipper;

 

public class RandomNumberKey extends Activity {
 EditText editText;
 ViewFlipper flipper;
 TableLayout tableLayout;
 
 private String passwordStr = "";
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        

        // 디바이스 화면에 따라 버튼 크기 설정
        final int btnWidth = getBtnWidth(); 
        
        flipper = (ViewFlipper)findViewById(R.id.viewFlipper);
        flipper.setVisibility(View.INVISIBLE);  // ViewFlipper 가 Activity 첫 실행시 보이지 않게 설정
        flipper.setInAnimation(appearSecurityKeyboardAnimation()); // 나타날때 애니메이션
        flipper.setOutAnimation(disappearSecurityKeyboardAnimation()); // 사라질때 애니메이션
        
        tableLayout = (TableLayout)findViewById(R.id.tableLayout);
        
        // 보안키보드의 오프 이미지를 표시하기 위해 임의의 empty view를 삽입
        TextView emptyView = new TextView(this);
        flipper.addView(emptyView, 0);  
        
        editText = (EditText)findViewById(R.id.editText);
        editText.setInputType(0); //가상키보드 오프
        editText.setOnClickListener(new OnClickListener() {
             public void onClick(View v) {
                // 보안 키보드 표시
                if(flipper.getCurrentView().getId() != R.id.firstViewFlipper){
                        reOrderKeyboard(btnWidth); // 보안키보드 숫자 랜덤배치
                        flipper.setVisibility(View.VISIBLE); // 보안키보드 보이도록 설정
                        flipper.setDisplayedChild(1); // viewflipper 에서 보안키보드 부분이 보이도록 set
                }
          }
     });
        
           keyboardClickHandler();
       }
    
    private int getBtnWidth(){
        DisplayMetrics displaymetrics = new DisplayMetrics();  
        getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);  
        int btnWidth = displaymetrics.widthPixels / 3; // 화면 너비 나누기 3으로 버튼 너비 설정
        
        return btnWidth;
    }
    
    private void reOrderKeyboard(int btnWidth){

     // 0부터 9까지의 수를 array list에 차례대로 넣는다.
     ArrayList<String> keyNumberArr = new ArrayList<String>();
     for(int i=0; i<10; i++){
      keyNumberArr.add(String.valueOf(i));
     }
     
     TableRow tr;
     Button key;
     int randumIndex;     
     Random random = new Random();
     
     for(int i=0; i<tableLayout.getChildCount(); i++){

      // 테이블의 한 로우를 받아옴
      tr = (TableRow) tableLayout.getChildAt(i);
      
      for(int j=0; j<tr.getChildCount(); j++){       

       // 한 컬럼을 받아옴
       key = (Button) tr.getChildAt(j);
       
       // 숫자키 체크 (XML 에서 숫자키에 id를 주지 않음)
       if(key.getId() == -1){
        randumIndex = random.nextInt(keyNumberArr.size()); // arraylist의 크기만큼의 범위에서 랜덤한 정수 생성
           key.setText(keyNumberArr.get(randumIndex)); // 해당 위치의 key에 text를 세팅
           key.setWidth(btnWidth); // key 버튼의 너비 설정
           keyNumberArr.remove(randumIndex); // 셋팅한 text를 arraylist에서 제거
           final String keyText = key.getText().toString(); // 셋팅된 key의 text를 임시저장
           
           key.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
             int curIndex = editText.getSelectionStart(); // 현재 에디트박스의 커서위치
             int passWordLength = passwordStr.length(); 
             
             passwordStr = passwordStr.substring(0, curIndex) + keyText + 
             passwordStr.substring(curIndex, passWordLength);  // 패스워드 String을 가지고 있음
             

             // 사용자에게 보이는 에디트 박스에는 *로 채움
             editText.setText(""); 
             for(int i=0; i<curIndex; i++){
              editText.append("*");
             }
             editText.append(keyText);
             for(int i=curIndex+1; i<passWordLength+1; i++){
              editText.append("*");
             }

            editText.setSelection(curIndex+1);
            }
           });
       }
      }
     }
    }
    
    private void keyboardClickHandler(){
     Button key_done = (Button)findViewById(R.id.key_done);
     Button key_backspace = (Button)findViewById(R.id.key_backspace);
     

    // 확인키 누름
     key_done.setOnClickListener(new View.OnClickListener() {
   public void onClick(View view) {

    // 현재 viewfliper가 가지고 있는 view가 키보드인지 체크
    if(flipper.getCurrentView().getId() == R.id.firstViewFlipper){

          // empty view 호출, 즉 키보드view를 퇴장시킴
           flipper.setDisplayedChild(0);
    }
   }
  });
    

     // backspace 키 입력 
     key_backspace.setOnClickListener(new View.OnClickListener() {
   public void onClick(View view) {
    // 현재 커서위치
       int curIndex = editText.getSelectionStart();
       // 현재 입력된 패스워드 길이
       int passWordLength = passwordStr.length();
       if((curIndex == 0) || (passWordLength == 0)){
        return;
       }
     

    // 한글자씩 지우기  
    passwordStr = passwordStr.substring(0, curIndex-1) + passwordStr.substring(curIndex, passWordLength);
    editText.setText("");
    for(int i=0; i<passWordLength-1; i++){
     editText.append("*");
    }
    editText.setSelection(curIndex-1);
   }
  });
    }
    
    /***************************************************/
    /** 애니메이션 설정 **/
    /***************************************************/
    private Animation appearSecurityKeyboardAnimation() {
     Animation appear = new TranslateAnimation(
     Animation.RELATIVE_TO_PARENT, 0.0f,
     Animation.RELATIVE_TO_PARENT, 0.0f,
     Animation.RELATIVE_TO_PARENT, +1.0f,
     Animation.RELATIVE_TO_PARENT, 0.0f);
     appear.setDuration(400);
     appear.setInterpolator(new AccelerateInterpolator());
     return appear;
    }
    
    private Animation disappearSecurityKeyboardAnimation() {
     Animation disappear = new TranslateAnimation(
     Animation.RELATIVE_TO_PARENT, 0.0f,
     Animation.RELATIVE_TO_PARENT, 0.0f,
     Animation.RELATIVE_TO_PARENT, 0.0f,
     Animation.RELATIVE_TO_PARENT, +1.0f);
     disappear.setDuration(400);
     disappear.setInterpolator(new DecelerateInterpolator());
     return disappear;
    }
    
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event){
     if(keyCode==KeyEvent.KEYCODE_BACK){

      // 디바이스 키중 Back버튼 눌렀을때 키보드가 올라와있으면 키보드 닫기
      if(flipper.getCurrentView().getId() == R.id.firstViewFlipper){
          flipper.setDisplayedChild(0);
   }

      // 키보드가 올라오지 않은 상태면 보통때의 back 버튼 수행
      else{
    super.onKeyDown(keyCode, event);
   }
     }
      
     return true;
    }
}

 

 

주석을 보면 다 이해하겠지만 viewflipper에 임의의 빈 textview를 하나 넣어 주어(0번째 인덱스에) child의 갯수를 2개로 만들어주었다.

 

그리고 키보드를 온 오프 할때는 viewflipper에서 키보드 view를 선택 / 빈 view를 선택하여 마치 하나의 view가 나오고 퇴장하는 효과처럼 보이게 하였다.

 

viewflipper는 하나의 child만 가지고 있으면 플리핑이 별도로 안되는 듯 하여 위와같은 꼼수(?)를 부렸다.

 

 

굿-_-b

 

 

 

 

4. 실행 화면

 [출처] [Android] ViewFlipper 활용하여 보안 키보드 만들기|작성자 노티  

반응형