Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android實現支付寶6位密碼輸入界面

Android實現支付寶6位密碼輸入界面

編輯:關於Android編程

 我們先來照圖分析一下:
(1)限制輸入6位,每一位都有自己的框格,每個格顯示一位;
(2)有回退/取消支付按鈕;
(3)有忘記密碼鏈接;
(4)自定義的只能輸入數字的鍵盤輸入區;
(5)在6位輸完後自動進行密碼校驗和支付交易。如上圖左邊是iOS支付寶支付密碼輸入控件,右邊是我模仿實現的效果。

首先,我們需要一個頁面來完成以上的靜態布局,.xml代碼如下:

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  android:layout_width="match_parent"  
  android:layout_height="match_parent"  
  android:background="#EEEEEE"  
  android:gravity="bottom">  
  
  <LinearLayout  
    android:id="@+id/linear_pass"  
    android:layout_width="match_parent"  
    android:layout_height="wrap_content"  
    android:orientation="vertical">  
  
    <RelativeLayout  
      android:layout_width="match_parent"  
      android:layout_height="wrap_content"  
      android:layout_margin="5dp">  
  
      <!-- 取消按鈕 -->  
      <ImageView  
        android:id="@+id/img_cancel"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:background="@drawable/icon_clean" />  
  
      <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_centerInParent="true"  
        android:text="輸入密碼"  
        android:textColor="#898181"  
        android:textSize="20sp" />  
    </RelativeLayout>  
  
    <View  
      android:layout_width="match_parent"  
      android:layout_height="0.5dp"  
      android:background="#555555" />  
  
    <!-- 6位密碼框布局,需要一個圓角邊框的shape作為layout的背景 -->  
    <LinearLayout  
      android:layout_width="match_parent"  
      android:layout_height="wrap_content"  
      android:layout_marginLeft="40dp"  
      android:layout_marginRight="40dp"  
      android:layout_marginTop="20dp"  
      android:background="@drawable/shape_input_area"  
      android:orientation="horizontal">  
  
      <!-- inputType設置隱藏密碼明文  
         textSize設置大一點,否則“點”太小了,不美觀 -->  
      <TextView  
        android:id="@+id/tv_pass1"  
        android:layout_width="0dp"  
        android:layout_height="wrap_content"  
        android:layout_weight="1"  
        android:gravity="center"  
        android:inputType="numberPassword"  
        android:textSize="32sp" />  
  
      <View  
        android:layout_width="1dp"  
        android:layout_height="match_parent"  
        android:background="#999999" />  
  
      <TextView  
        android:id="@+id/tv_pass2"  
        android:layout_width="0dp"  
        android:layout_height="wrap_content"  
        android:layout_weight="1"  
        android:gravity="center"  
        android:inputType="numberPassword"  
        android:textSize="32sp" />  
  
      <View  
        android:layout_width="1dp"  
        android:layout_height="match_parent"  
        android:background="#999999" />  
  
      <TextView  
        android:id="@+id/tv_pass3"  
        android:layout_width="0dp"  
        android:layout_height="wrap_content"  
        android:layout_weight="1"  
        android:gravity="center"  
        android:inputType="numberPassword"  
        android:textSize="32sp" />  
  
      <View  
        android:layout_width="1dp"  
        android:layout_height="match_parent"  
        android:background="#999999" />  
  
      <TextView  
        android:id="@+id/tv_pass4"  
        android:layout_width="0dp"  
        android:layout_height="wrap_content"  
        android:layout_weight="1"  
        android:gravity="center"  
        android:inputType="numberPassword"  
        android:textSize="32sp" />  
  
      <View  
        android:layout_width="1dp"  
        android:layout_height="match_parent"  
        android:background="#999999" />  
  
      <TextView  
        android:id="@+id/tv_pass5"  
        android:layout_width="0dp"  
        android:layout_height="wrap_content"  
        android:layout_weight="1"  
        android:gravity="center"  
        android:inputType="numberPassword"  
        android:textSize="32sp" />  
  
      <View  
        android:layout_width="1dp"  
        android:layout_height="match_parent"  
        android:background="#999999" />  
  
      <TextView  
        android:id="@+id/tv_pass6"  
        android:layout_width="0dp"  
        android:layout_height="wrap_content"  
        android:layout_weight="1"  
        android:gravity="center"  
        android:inputType="numberPassword"  
        android:textSize="32sp" />  
    </LinearLayout>  
  
    <!-- 忘記密碼鏈接 -->  
    <TextView  
      android:id="@+id/tv_forgetPwd"  
      android:layout_width="wrap_content"  
      android:layout_height="wrap_content"  
      android:layout_gravity="right"  
      android:layout_margin="15dp"  
      android:text="忘記密碼?"  
      android:textColor="#354EEF" />  
  </LinearLayout>  
  
  <!-- 輸入鍵盤 -->  
  <GridView  
    android:id="@+id/gv_keybord"  
    android:layout_width="match_parent"  
    android:layout_height="wrap_content"  
    android:layout_below="@id/linear_pass"  
    android:layout_marginTop="40dp"  
    android:background="@android:color/black"  
    android:horizontalSpacing="0.5dp"  
    android:numColumns="3"  
    android:verticalSpacing="0.5dp" />  
</RelativeLayout>  

其中需要圓角背景shape_input_area.xml:

<?xml version="1.0" encoding="utf-8"?>  
<shape xmlns:android="http://schemas.android.com/apk/res/android">  
  <corners android:radius="5dp"/>  
  <stroke android:color="@android:color/darker_gray"  
    android:width="1dp"/>  
  <solid android:color="@android:color/white"/>  
</shape>  

需要數字按鈕的背景selector_gride.xml:

<?xml version="1.0" encoding="utf-8"?>  
<selector xmlns:android="http://schemas.android.com/apk/res/android">  
  <item android:state_enabled="false">  
    <shape>  
      <solid android:color="#C0C4C7" />  
    </shape>  
  </item>  
  <item android:state_enabled="true" android:state_pressed="false">  
    <shape>  
      <solid android:color="@android:color/white" />  
    </shape>  
  </item>  
  <item android:state_enabled="true" android:state_pressed="true">  
    <shape>  
      <solid android:color="#C0C4C7" />  
    </shape>  
  </item>  
</selector>  

需要回退鍵背景selector_key_del.xml:

<?xml version="1.0" encoding="utf-8"?>  
<selector xmlns:android="http://schemas.android.com/apk/res/android">  
  <item android:state_enabled="false">  
    <shape>  
      <solid android:color="#C0C4C7" />  
    </shape>  
  </item>  
  <item android:state_enabled="true" android:state_pressed="false">  
    <shape>  
      <solid android:color="#C0C4C7" />  
    </shape>  
  </item>  
  <item android:state_enabled="true" android:state_pressed="true">  
    <shape>  
      <solid android:color="@android:color/white" />  
    </shape>  
  </item>  
</selector>  

下面來完成我們的自定義控件PasswordView.Java:

public class PasswordView extends RelativeLayout implements View.OnClickListener {  
  Context context;  
  
  private String strPassword;   //輸入的密碼  
  private TextView[] tvList;   //用數組保存6個TextView,為什麼用數組?  
                  //因為就6個輸入框不會變了,用數組內存申請固定空間,比List省空間(自己認為)  
  private GridView gridView;  //用GrideView布局鍵盤,其實並不是真正的鍵盤,只是模擬鍵盤的功能  
  private ArrayList<Map<String, String>> valueList;  //有人可能有疑問,為何這裡不用數組了?  
                            //因為要用Adapter中適配,用數組不能往adapter中填充  
  
  private ImageView imgCancel;  
  private TextView tvForget;  
  private int currentIndex = -1;  //用於記錄當前輸入密碼格位置  
  
  public PasswordView(Context context) {  
    this(context, null);  
  }  
  
  public PasswordView(Context context, AttributeSet attrs) {  
    super(context, attrs);  
    this.context = context;  
    View view = View.inflate(context, R.layout.layout_popup_bottom, null);  
      
    valueList = new ArrayList<Map<String, String>>();  
    tvList = new TextView[6];  
      
    imgCancel = (ImageView) view.findViewById(R.id.img_cancel);  
    imgCancel.setOnClickListener(this);  
  
    tvForget = (TextView) findViewById(R.id.tv_forgetPwd);  
    tvForget.setOnClickListener(this);  
      
    tvList[0] = (TextView) view.findViewById(R.id.tv_pass1);  
    tvList[1] = (TextView) view.findViewById(R.id.tv_pass2);  
    tvList[2] = (TextView) view.findViewById(R.id.tv_pass3);  
    tvList[3] = (TextView) view.findViewById(R.id.tv_pass4);  
    tvList[4] = (TextView) view.findViewById(R.id.tv_pass5);  
    tvList[5] = (TextView) view.findViewById(R.id.tv_pass6);  
  
    gridView = (GridView) view.findViewById(R.id.gv_keybord);  
  
    setView();  
      
    addView(view);   //必須要,不然不顯示控件  
  }  
  
  @Override  
  public void onClick(View v) {  
    switch (v.getId()) {  
      case R.id.img_cancel:  
        Toast.makeText(context, "Cancel", Toast.LENGTH_SHORT).show();  
        break;  
      case R.id.tv_forgetPwd:  
        Toast.makeText(context, "Forget", Toast.LENGTH_SHORT).show();  
        break;  
    }  
  }  
  
  private void setView() {  
    /* 初始化按鈕上應該顯示的數字 */  
    for (int i = 1; i < 13; i++) {  
      Map<String, String> map = new HashMap<String, String>();  
      if (i < 10) {  
        map.put("name", String.valueOf(i));  
      } else if (i == 10) {  
        map.put("name", "");  
      } else if (i == 12) {  
        map.put("name", "<<-");  
      } else if (i == 11) {  
        map.put("name", String.valueOf(0));  
      }  
      valueList.add(map);  
    }  
  
    gridView.setAdapter(adapter);  
    gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {  
      @Override  
      public void onItemClick(AdapterView<?> parent, View view, int position, long id) {  
        if (position < 11 && position != 9) {  //點擊0~9按鈕  
          if (currentIndex >= -1 && currentIndex < 5) {   //判斷輸入位置————要小心數組越界  
            tvList[++currentIndex].setText(valueList.get(position).get("name"));  
          }  
        } else {  
          if (position == 11) {   //點擊退格鍵  
            if (currentIndex - 1 >= -1) {   //判斷是否刪除完畢————要小心數組越界  
              tvList[currentIndex--].setText("");  
            }  
          }  
        }  
      }  
    });  
  }  
  
  //設置監聽方法,在第6位輸入完成後觸發  
  public void setOnFinishInput(final OnPasswordInputFinish pass) {  
    tvList[5].addTextChangedListener(new TextWatcher() {  
      @Override  
      public void beforeTextChanged(CharSequence s, int start, int count, int after) {  
  
      }  
  
      @Override  
      public void onTextChanged(CharSequence s, int start, int before, int count) {  
  
      }  
  
      @Override  
      public void afterTextChanged(Editable s) {  
        if (s.toString().length() == 1) {  
          strPassword = "";   //每次觸發都要先將strPassword置空,再重新獲取,避免由於輸入刪除再輸入造成混亂  
          for (int i = 0; i < 6; i++) {  
            strPassword += tvList[i].getText().toString().trim();  
          }  
          pass.inputFinish();  //接口中要實現的方法,完成密碼輸入完成後的響應邏輯  
        }  
      }  
    });  
  }  
  
  /* 獲取輸入的密碼 */  
  public String getStrPassword() {  
    return strPassword;  
  }  
  
  /* 暴露取消支付的按鈕,可以靈活改變響應 */  
  public ImageView getCancelImageView() {  
    return imgCancel;  
  }  
  
  /* 暴露忘記密碼的按鈕,可以靈活改變響應 */  
  public TextView getForgetTextView() {  
    return tvForget;  
  }  
  
  //GrideView的適配器  
  BaseAdapter adapter = new BaseAdapter() {  
    @Override  
    public int getCount() {  
      return valueList.size();  
    }  
  
    @Override  
    public Object getItem(int position) {  
      return valueList.get(position);  
    }  
  
    @Override  
    public long getItemId(int position) {  
      return position;  
    }  
  
    @Override  
    public View getView(int position, View convertView, ViewGroup parent) {  
      ViewHolder viewHolder;  
      if (convertView == null) {  
        convertView = View.inflate(context, R.layout.item_gride, null);  
        viewHolder = new ViewHolder();  
        viewHolder.btnKey = (TextView) convertView.findViewById(R.id.btn_keys);  
        convertView.setTag(viewHolder);  
      } else {  
        viewHolder = (ViewHolder) convertView.getTag();  
      }  
      viewHolder.btnKey.setText(valueList.get(position).get("name"));  
      if(position == 9){  
        viewHolder.btnKey.setBackgroundResource(R.drawable.selector_key_del);  
        viewHolder.btnKey.setEnabled(false);  
      }  
      if(position == 11){  
        viewHolder.btnKey.setBackgroundResource(R.drawable.selector_key_del);  
      }  
  
      return convertView;  
    }  
  };  
  
  /** 
   * 存放控件 
   */  
  public final class ViewHolder {  
    public TextView btnKey;  
  }  
}  

自認為代碼注釋還是可以的。就是在實現過程中要注意數組的越界問題,在輸入邏輯響應中要注意邏輯處理,也就是grideView的OnItemClickListener事件處理。其中用到自定義的接口OnPasswordInputFinish來實現輸入完成的事件回掉:

/** 
 * Belong to the Project —— MyPayUI  
 * Created by WangJ on 2015/11/25 17:15. 
 *  
 * 自定義接口,用於給密碼輸入完成添加回掉事件 
 */  
public interface OnPasswordInputFinish {  
  void inputFinish();  
}  

還有就是Adapter中用到的每個按鈕Item的布局item_gride.xml:

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  android:layout_width="match_parent"  
  android:layout_height="match_parent">  
  
  <!-- 模擬鍵盤按鈕,當然你可以用Button,但要注意Button和GrideView的點擊響應問題 -->  
  <TextView  
    android:id="@+id/btn_keys"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:padding="10dp"  
    android:gravity="center"  
    android:textSize="25sp"  
    android:background="@drawable/selector_gride"/>  
</LinearLayout> 

好了,到此我們的自定義控件——模仿支付寶6位支付密碼輸入控件就完成了,下邊我們在Activity中用一下,檢驗一下效果:
我們在MianActivity中用用一下我們定義好的控件:

public class MainActivity extends Activity {  
  
  @Override  
  protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
      
    /************* 第一種用法————開始 ***************/  
    setContentView(R.layout.activity_main);  
  
    final PasswordView pwdView = (PasswordView) findViewById(R.id.pwd_view);  
      
    //添加密碼輸入完成的響應  
    pwdView.setOnFinishInput(new OnPasswordInputFinish() {  
      @Override  
      public void inputFinish() {  
        //輸入完成後我們簡單顯示一下輸入的密碼  
        //也就是說——>實現你的交易邏輯什麼的在這裡寫  
        Toast.makeText(MainActivity.this, pwdView.getStrPassword(), Toast.LENGTH_SHORT).show();  
      }  
    });  
      
    /** 
     * 可以用自定義控件中暴露出來的cancelImageView方法,重新提供相應 
     * 如果寫了,會覆蓋我們在自定義控件中提供的響應 
     * 可以看到這裡toast顯示 "Biu Biu Biu"而不是"Cancel"*/  
    pwdView.getCancelImageView().setOnClickListener(new View.OnClickListener() {  
      @Override  
      public void onClick(View v) {  
        Toast.makeText(MainActivity.this, "Biu Biu Biu", Toast.LENGTH_SHORT).show();  
      }  
    });  
    /************ 第一種用法————結束 ******************/  
  
      
    /************* 第二種用法————開始 *****************/  
//    final PasswordView pwdView = new PasswordView(this);  
//    setContentView(pwdView);  
//    pwdView.setOnFinishInput(new OnPasswordInputFinish() {  
//      @Override  
//      public void inputFinish() {  
//        Toast.makeText(MainActivity.this, pwdView.getStrPassword(), Toast.LENGTH_SHORT).show();  
//      }  
//    });  
    /************** 第二種用法————結束 ****************/  
  }  
}  

在第一種方法中我們用到的布局文件:

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout  
  android:id="@+id/xxx"  
  xmlns:android="http://schemas.android.com/apk/res/android"  
  android:layout_width="match_parent"  
  android:layout_height="match_parent"  
  android:background="#624762">  
  
  <com.wangj.mypayview.PasswordView  
    android:id="@+id/pwd_view"  
    android:layout_width="match_parent"  
    android:layout_height="wrap_content"  
    android:layout_alignParentBottom="true"/>  
</RelativeLayout> 

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved