1.登陆界面
对于一个网络APP来说,刚开始首先必须登录,膜拜使用有手机登陆,当然还有微信什么其他的,不过绑定微信后又要绑定手机,所以手机登陆是必须的。
先看效果图:
2.界面还比较简单,两个et 和两个bt.
xml文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.yiwen.mobike.views.MyToolBar
android:id="@+id/toolbar_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:leftButtonIcon="@drawable/places_ic_clear"
app:showSearchView="false"
app:title="手机验证"
>
</com.yiwen.mobike.views.MyToolBar>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/toolbar_login"
android:layout_margin="20dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#F2F2F2"
android:orientation="horizontal">
<TextView
android:layout_marginLeft="3dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="手机号"
android:textColor="#333333"
android:textSize="18dp"/>
<com.yiwen.mobike.views.ClearEditText
android:id="@+id/et_phone"
android:layout_marginRight="3dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入手机号"
android:inputType="phone"
android:textColorHint="#ABABAB"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:background="#F2F2F2"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_marginLeft="3dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="验证码"
android:textColor="#333333"
android:textSize="18dp"/>
<EditText
android:id="@+id/et_code"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:hint="请输入验证码"
android:inputType="phone"
android:textColorHint="#ABABAB"/>
<Button
android:id="@+id/get_code"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:background="@color/gray"
android:text="获取验证码"
android:textColor="@color/white"/>
</LinearLayout>
<TextView
android:id="@+id/loin_voice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:layout_marginTop="8dp"
android:clickable="true"
android:text="收不到短信,试试语音短信"
android:textColor="@color/red"/>
<Button
android:id="@+id/login_query"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@color/gray"
android:text="确定"
android:textColor="@color/white"/>
<LinearLayout
android:layout_marginTop="15dp"
android:gravity="center"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
<TextView
android:text="点击-确定,即表示已阅读并同意"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/login_services"
android:text="《用车服务条款》"
android:textColor="@color/red"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
其中
3.MyToolBar和ClearEditText 为自定义控件。
myToolBar代码:
package com.yiwen.mobike.views;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.annotation.StringRes;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.TintTypedArray;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import com.yiwen.mobike.R;
/**
* User: Yiwen(https://github.com/yiwent)
* Date: 2017-05-02
* Time: 11:00
* FIXME
*/
public class MyToolBar extends Toolbar {
private LayoutInflater mInflater;
private View mView;
private TextView toolbar_title;
private EditText toolbar_searchview;
private ImageView toolbar_leftButton;
private ImageView toolbar_rightButton;
private boolean showSearchView;
private Drawable left_button_icon;
private Drawable right_button_icon;
private String title;
public MyToolBar(Context context) {
this(context, null);
}
public MyToolBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyToolBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initview();
if (attrs != null) {
final TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
R.styleable.MyToolBar, defStyleAttr, 0);
showSearchView = a.getBoolean(R.styleable.MyToolBar_showSearchView, false);
left_button_icon = a.getDrawable(R.styleable.MyToolBar_leftButtonIcon);
right_button_icon = a.getDrawable(R.styleable.MyToolBar_rightButtonIcon);
title = a.getString(R.styleable.MyToolBar_myTitle);
a.recycle();
}
isShouw();
setContentInsetsRelative(15, 15);
initListener();
}
private void initListener() {
toolbar_leftButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (onLeftButtonClickListener != null) {
onLeftButtonClickListener.onClick();
}
}
});
toolbar_rightButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (onRightButtonClickListener != null) {
onRightButtonClickListener.onClick();
}
}
});
}
public void isShouw() {
if (showSearchView) {
showSearchview();
hideTitle();
} else {
hideSearchview();
showTitle();
if (title != null) {
toolbar_title.setText(title);
}
}
Log.d("left_button_icon", "initview:5"+left_button_icon);
if (left_button_icon != null) {
toolbar_leftButton.setVisibility(VISIBLE);
toolbar_leftButton.setBackground(left_button_icon);
}
if (right_button_icon != null) {
toolbar_rightButton.setVisibility(VISIBLE);
toolbar_rightButton.setImageDrawable(right_button_icon);
}
}
public interface OnLeftButtonClickListener {
void onClick();
}
public interface OnRightButtonClickListener {
void onClick();
}
private OnLeftButtonClickListener onLeftButtonClickListener;
private OnRightButtonClickListener onRightButtonClickListener;
public void setOnLeftButtonClickListener(OnLeftButtonClickListener listener) {
onLeftButtonClickListener = listener;
}
public void setOnRightButtonClickListener(OnRightButtonClickListener listener) {
onRightButtonClickListener = listener;
}
private void initview() {
if (mView == null) {
mInflater = LayoutInflater.from(getContext());
mView = mInflater.inflate(R.layout.toolbar, null);
toolbar_rightButton = (ImageView) mView.findViewById(R.id.id_btn_right);
toolbar_title = (TextView) mView.findViewById(R.id.id_tv_title);
toolbar_searchview = (EditText) mView.findViewById(R.id.id_et_search);
toolbar_leftButton = (ImageView) mView.findViewById(R.id.id_ib_navigation);
ActionBar.LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
addView(mView, lp);
// if (showSearchView) {
// showSearchview();
// hideTitle();
// } else {
// hideSearchview();
// showTitle();
// if (title != null) {
// toolbar_title.setText(title);
// }
// }
// Log.d("left_button_icon", "initview:5"+left_button_icon);
// if (left_button_icon != null) {
//
// toolbar_leftButton.setBackground(left_button_icon);
// toolbar_leftButton.setVisibility(VISIBLE);
// }
//
// if (right_button_icon != null) {
// toolbar_rightButton.setImageDrawable(right_button_icon);
// toolbar_rightButton.setVisibility(VISIBLE);
// }
}
}
@Override
public void setTitle(@StringRes int resId) {
setTitle(getContext().getString(resId));
}
@Override
public void setTitle(CharSequence title) {
initview();
if (toolbar_title != null) {
toolbar_title.setText(title);
showTitle();
}
}
public void showSearchview() {
if (toolbar_searchview != null) {
toolbar_searchview.setVisibility(VISIBLE);
}
}
public void hideSearchview() {
if (toolbar_searchview != null) {
toolbar_searchview.setVisibility(GONE);
}
}
public void showTitle() {
if (toolbar_title != null) {
toolbar_title.setVisibility(VISIBLE);
}
}
public void hideTitle() {
if (toolbar_title != null) {
toolbar_title.setVisibility(GONE);
}
}
/**
* 设置左右按钮的图标
*
* @param d
*/
public void setLeftButtonIconDrawable(Drawable d) {
toolbar_leftButton.setImageDrawable(d);
toolbar_leftButton.setVisibility(VISIBLE);
}
public void setRightButtonIconDrawable(Drawable d) {
toolbar_rightButton.setImageDrawable(d);
toolbar_rightButton.setVisibility(VISIBLE);
}
/**
* 标题与搜索框的切换
*/
public void setShowSearchView() {
hideTitle();
showSearchview();
}
public void setShowTitleView(String title) {
hideSearchview();
showTitle();
toolbar_title.setText(title);
}
}
4.ClearEditText代码:
非常简单的自定义控件,加了几个属性。package com.yiwen.mobike.views; import android.content.Context; import android.graphics.drawable.Drawable; import android.support.v4.content.ContextCompat; import android.support.v4.graphics.drawable.DrawableCompat; import android.support.v7.widget.AppCompatEditText; import android.text.Editable; import android.text.TextWatcher; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import com.yiwen.mobike.R; public class ClearEditText extends AppCompatEditText implements View.OnTouchListener, View.OnFocusChangeListener, TextWatcher { private Drawable mClearTextIcon; private OnFocusChangeListener mOnFocusChangeListener; private OnTouchListener mOnTouchListener; public ClearEditText(final Context context) { super(context); init(context); } public ClearEditText(final Context context, final AttributeSet attrs) { super(context, attrs); init(context); } public ClearEditText(final Context context, final AttributeSet attrs, final int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(final Context context) { final Drawable drawable = ContextCompat.getDrawable(context, R.mipmap.places_ic_clear); final Drawable wrappedDrawable = DrawableCompat.wrap(drawable); //Wrap the drawable so that it can be tinted pre Lollipop DrawableCompat.setTint(wrappedDrawable, getCurrentHintTextColor()); mClearTextIcon = wrappedDrawable; // mClearTextIcon= context.getResources().getDrawable(R.drawable.icon_delete_32); mClearTextIcon.setBounds(0, 0, mClearTextIcon.getIntrinsicHeight(), mClearTextIcon.getIntrinsicHeight()); setClearIconVisible(false); /* * 设置父类的监听器,还可以单独给该类设置监听器 * */ super.setOnTouchListener(this); super.setOnFocusChangeListener(this); addTextChangedListener(this); } @Override public void setOnFocusChangeListener(OnFocusChangeListener l) { mOnFocusChangeListener = l; } @Override public void setOnTouchListener(OnTouchListener l) { mOnTouchListener = l; } @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { setClearIconVisible(getText().length() > 0); } else { setClearIconVisible(false); } if (mOnFocusChangeListener != null) { mOnFocusChangeListener.onFocusChange(v, hasFocus); } } @Override public boolean onTouch(View view, MotionEvent motionEvent) { final int x = (int) motionEvent.getX(); /* 判断是否触摸在清楚按钮上 * */ if (mClearTextIcon.isVisible() && x > getWidth() - getPaddingRight() - mClearTextIcon.getIntrinsicWidth()) { if (motionEvent.getAction() == MotionEvent.ACTION_UP) { setError(null); setText(""); } return true; } return mOnTouchListener != null && mOnTouchListener.onTouch(view, motionEvent); } @Override public final void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { if (isFocused()) { setClearIconVisible(text.length() > 0); } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { } private void setClearIconVisible(final boolean visible) { mClearTextIcon.setVisible(visible, false); final Drawable[] compoundDrawables = getCompoundDrawables(); setCompoundDrawables( compoundDrawables[0], compoundDrawables[1], visible ? mClearTextIcon : null, compoundDrawables[3]); } }
5.LoginActivity包含手机验证,和判断手机输入对错,控制控件颜色,膜拜主色为黑 、白、红还有灰色。
package com.yiwen.mobike.activity; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import com.yiwen.mobike.R; import com.yiwen.mobike.utils.MyConstains; import com.yiwen.mobike.utils.ToastUtils; import com.yiwen.mobike.views.ClearEditText; import com.yiwen.mobike.views.CountTimerView; import com.yiwen.mobike.views.MyToolBar; import org.json.JSONObject; import java.util.ArrayList; import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import cn.smssdk.EventHandler; import cn.smssdk.SMSSDK; import cn.smssdk.utils.SMSLog; public class LoginActivity extends AppCompatActivity { private static final String TAG = "LoginActivity"; @BindView(R.id.toolbar_login) MyToolBar mToolbarLogin; @BindView(R.id.et_phone) ClearEditText mEtPhone; @BindView(R.id.et_code) EditText mEtCode; @BindView(R.id.get_code) Button mGetCode; @BindView(R.id.loin_voice) TextView mLoinVoice; @BindView(R.id.login_query) Button mLoginQuery; @BindView(R.id.login_services) TextView mLoginServices; private boolean isNeedLogin = true; private TextView mTvCountryCode; private CountTimerView mCountTimeView; private int phoneLength = 0; private int codeLength = 0; // 默认使用中国区号 private static final String DEFAULT_COUNTRY_ID = "42"; private SmsEventHandler mEventHandler; private boolean isSendCode; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); ButterKnife.bind(this); intView(); initDate(); initEvent(); } private void intView() { ButterKnife.bind(this); } private void initDate() { SMSSDK.initSDK(this, "1dfed2cdde843", "4266d445a7c298caecfb04ecb165fde7"); mEventHandler = new SmsEventHandler(); SMSSDK.registerEventHandler(mEventHandler); } private void initEvent() { mToolbarLogin.setOnLeftButtonClickListener(new MyToolBar.OnLeftButtonClickListener() { @Override public void onClick() { Go2Main(); } }); mEtPhone.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) { phoneLength = s.length(); if (phoneLength > 0) { setRed(mGetCode); } else { setGray(mGetCode); } if (phoneLength > 0 && codeLength > 0) { setRed(mLoginQuery); } else { setGray(mLoginQuery); } } @Override public void afterTextChanged(Editable s) { } }); mEtCode.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) { codeLength = s.length(); if (phoneLength > 0 && codeLength > 0) { setRed(mLoginQuery); } else { setGray(mLoginQuery); } } @Override public void afterTextChanged(Editable s) { } }); } /** * 改变bt颜色red设置可点击 * * @param bt */ private void setRed(Button bt) { bt.setClickable(true); bt.setBackgroundResource(R.color.red); } /** * 改变bt颜色gray设置不可点击 * * @param bt */ private void setGray(Button bt) { bt.setClickable(false); bt.setBackgroundResource(R.color.gray); } class SmsEventHandler extends EventHandler { @Override public void afterEvent(final int event, final int result, final Object data) { runOnUiThread(new Runnable() { @Override public void run() { //回调完成 if (result == SMSSDK.RESULT_COMPLETE) { //返回支持发送验证码的国家列表 if (event == SMSSDK.EVENT_GET_SUPPORTED_COUNTRIES) { // SMSSDK.getSupportedCountries(); onCountryListGot((ArrayList<HashMap<String, Object>>) data); //获取验证码成功 } else if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE) { // 请求验证码后,跳转到验证码填写页面 afterVerificationCodeRequested((Boolean) data); //提交验证码成功 } else if (event == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE) { // ToastUtils.show(LoginActivity.this, "验证码已发送"); mEtCode.setText(""); RegOK(); } } else { // 根据服务器返回的网络错误,给toast提示 try { ((Throwable) data).printStackTrace(); Throwable throwable = (Throwable) data; JSONObject object = new JSONObject( throwable.getMessage()); String des = object.optString("detail"); if (!TextUtils.isEmpty(des)) { ToastUtils.show(LoginActivity.this, des); return; } } catch (Exception e) { SMSLog.getInstance().w(e); } } } }); } private void RegOK() { // ToastUtils.show(LoginActivity.this, "注册成功"); getSharedPreferences(MyConstains.IS_NEED_LOGIN, MODE_PRIVATE) .edit() .putBoolean(MyConstains.IS_NEED_LOGIN, false) .apply(); Go2Main(); } } /** * 获得支持的国家列表 * * @param data */ private void onCountryListGot(ArrayList<HashMap<String, Object>> data) { for (HashMap<String, Object> country : data) { String code = (String) country.get("zone"); String rule = (String) country.get("rule"); if (TextUtils.isEmpty(code) || TextUtils.isEmpty(rule)) { continue; } Log.d(TAG, "onCountryListGot: " + code + ":" + rule); } } /** * 请求验证码成功后跳转 * * @param data */ private void afterVerificationCodeRequested(Boolean data) { String phone = mEtPhone.getText().toString().trim().replace("\\s*", ""); // String countryCode = mTvCountryCode.getText().toString().trim(); String countryCode = "86"; if (countryCode.startsWith("+")) { countryCode = countryCode.substring(1); } isSendCode = false; } private void Go2Main() { Intent intent = new Intent(LoginActivity.this, MainActivity.class); startActivity(intent); finish(); } @OnClick({R.id.get_code, R.id.loin_voice, R.id.login_query, R.id.login_services}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.get_code: getCode(); break; case R.id.loin_voice: ToastUtils.show(LoginActivity.this,"语音验证"); break; case R.id.login_query: submitCode(); break; case R.id.login_services: ToastUtils.show(LoginActivity.this,"服务点击"); break; } } /** * 获取验证码 */ private void getCode() { String phone = mEtPhone.getText().toString().trim().replace("\\s*", ""); // String countryCode = mTvCountryCode.getText().toString().trim(); String countryCode = "+86"; // String countryCode = mTvCountryCode.getText().toString().trim(); if (checkPhoneNum(phone, countryCode)) { /*请求获得验证码*/ Log.d(TAG, "getCode: " + phone + "**" + countryCode); SMSSDK.getVerificationCode(countryCode, phone); mCountTimeView = new CountTimerView(mGetCode); mCountTimeView.start(); } } /** * 检查手机号格式 * * @param phone * @param countryCode */ private boolean checkPhoneNum(String phone, String countryCode) { if (countryCode.startsWith("+")) { countryCode = countryCode.substring(1); } if (TextUtils.isEmpty(phone)) { mEtPhone.setError("手机号格式有误"); //ToastUtils.show(this, "请输入手机号码"); // dissmissDialog(); return false; } if (countryCode.equals("86")) { if (phone.length() != 11) { mEtPhone.setError("手机号长度不正确"); // ToastUtils.show(this, "手机号长度不正确"); // dissmissDialog(); return false; } } String rule = "^1(3|5|7|8|4)\\d{9}"; Pattern compile = Pattern.compile(rule); Matcher matcher = compile.matcher(phone); if (!matcher.matches()) { mEtPhone.setError("您输入的手机号码格式不正确"); // ToastUtils.show(this, "您输入的手机号码格式不正确"); // dissmissDialog(); return false; } return true; } private void submitCode() { String code = mEtCode.getText().toString().trim(); String mPhone = mEtPhone.getText().toString().trim().replace("\\s*", ""); if (TextUtils.isEmpty(code)) { mEtCode.setError("请输入验证码"); // ToastUtils.show(this, "请输入验证码"); return; } Log.d(TAG, "submitCode: " + mPhone + code); SMSSDK.submitVerificationCode("86", mPhone, code); } @Override protected void onDestroy() { super.onDestroy(); SMSSDK.unregisterEventHandler(mEventHandler); } }
6.最后说明:验证手机号用了mob的SDK,经测试还是可以发短信的,不过用同一号码,两三次就没有用了,估计是仿真频繁获取短信吧今天就到这里了,具体代码可以到GitHub下载查看github代码下载:yiwent写博客不容易,喜欢希望多给个start,老铁,抱拳了。