先来个登录和注册吧
用了Material Design的风格
1.引路Material Design的库
implementation 'com.android.support:design:28.0.0'复制代码
修改主题文件
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="colorControlNormal">#D3D3D3</item>
<item name="colorControlActivated">@color/colorPrimary</item>
</style>复制代码
?colorAccent 是哪里的颜色?是系统特定内容的颜色,类似的颜色statusBarColor、windowBackground,看这张图你就明白了
文本没有获取焦点的文字颜色:android:textColorHint
下划线没有获取焦点的颜色:colorControlNormal
下划线获取焦点的颜色:colorControlActivated
TextInputLayout取值:不需要通过获取TextView这样的string userNameText = userName.EditText.Text;
完整的登录界面代码:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:paddingTop="56dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="72dp"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:text="彩虹bbs"
android:textColor="#000"
android:textSize="20sp" />
<!-- Email Label -->
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp">
<EditText
android:id="@+id/input_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入手机号或邮箱"
android:inputType="textEmailAddress|phone"
android:textColor="#D3D3D3" />
</android.support.design.widget.TextInputLayout>
<!-- Password Label -->
<android.support.design.widget.TextInputLayout
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp">
<EditText
android:id="@+id/input_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入密码"
android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout>
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:layout_marginTop="24dp"
android:background="@drawable/login_btn_selector"
android:padding="12dp"
android:enabled="false"
android:text="登录"
android:textColor="@color/color_white" />
<ProgressBar
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:gravity="center"
android:visibility="invisible" />
<TextView
android:id="@+id/link_signup"
android:clickable="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:gravity="center"
android:text="没有账号?注册一个"
android:textColor="#D3D3D3"
android:textSize="16sp" />
</LinearLayout>
</ScrollView>复制代码
用了MVP的设计模式,好像都有新的框架了
MVP 即模型-视图-呈现器
M:负责业务逻辑和实体模式
V:对应Activity,负责view的绘制和与用户交互
P:负责完成View于Model间的交互
MVP模式通过Presenter实现数据和视图之间的交互, 简化了Activity的职责。 同时
即避免了View和Model的直接联系, 又通过Presenter实现两者之间的沟通。
用户登录就是MVP的简单实现
结构图:
1.mode层
这里把数据存在了本地的sqlite中
- 实体类存放用户数据
- 接口要处理的业务逻辑
- 接口实现类业务逻辑的具体实现
public class User {
private String userName;
private String passWord;
public void setUserName(String userName) {
this.userName = userName;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public String getUserName() {
return userName;
}
public String getPassWord() {
return passWord;
}
@Override
public String toString() {
return "User{" +
"password='" + passWord + '\'' +
", username='" + userName + '\'' +
'}';
}
}复制代码
封装了用户数据,便于传递
接口
public interface LoginModel {
void login(User user, OnLoginFinishedListener onLoginFinishedListener);
}复制代码
其中OnLoginFinishedListener 是presenter层的接口, 方便实现回调presenter, 通
知presenter业务逻辑的返回结果
接口实现类
public class LoginModelImpl implements LoginModel {
@Override
public void login(User user, final OnLoginFinishedListener onLoginFinishedListener) {
final String userName = user.getUserName();
final String passWord = user.getPassWord();
new android.os.Handler().postDelayed(new Runnable() {
boolean iserror = false;
@Override
public void run() {
List<DataUser> users = DataSupport.select("usernum", "userpsd").where("usernum = ?", userName).limit(1).find(DataUser.class);
if (users.size() > 0) {
String usernum = users.get(0).getUsernum();
String userpsd = users.get(0).getUserpsd();
if (!TextUtils.isEmpty(userName)) {
if (userName.equals(usernum)) {
iserror = false;
} else {
onLoginFinishedListener.usernameError(ConStant.USER_ERROR);
iserror = true;
}
} else {
onLoginFinishedListener.usernameError(ConStant.USER_ISEMPTY);
iserror = true;
}
if (!TextUtils.isEmpty(passWord)) {
if (passWord.equals(userpsd)) {
iserror = false;
} else {
onLoginFinishedListener.passwordError(ConStant.PASSWORD_ERROR);
iserror = true;
}
} else {
onLoginFinishedListener.passwordError(ConStant.PASSWORD_ISEMPTY);
iserror = true;
}
} else {
onLoginFinishedListener.usernameError(ConStant.USER_ERROR);
iserror = true;
}
if (!iserror) {
onLoginFinishedListener.sucess();
}
}
}, 1000);
}
}
复制代码
有非空判断,根据用户名从数据库中匹配密码正确则登录成功,或者登录失败。模拟登陆延迟1秒
2.View层
- 接口,根据Activity的控件
- 接口实现类,即登录Activity要实现接口
switch (e) {
case ConStant.PASSWORD_ISEMPTY:
input_password.setError(getString(R.string.password_isempty));
break;
case ConStant.PASSWORD_ERROR:
input_password.setError(getString(R.string.password_error));
break;
}复制代码
根据不同的错误代码有不同的错误提示
3.Presenter层
Presenter是用作Model和View之间交互的桥梁。 从上图的包结构图中可以看出,Presenter包含内容:
①接口, 包含Presenter需要进行Model和View之间交互逻辑的接口, 以及上面提到
的Model层数据请求完成后回调的接口。
②接口实现类, 即实现具体的Presenter类逻辑。
//处理从model中传来的数据
public interface OnLoginFinishedListener {
void usernameError(int errorCode);
void passwordError(int errorCode);
void sucess();
}复制代码
//model与view进行交互
public interface LoginPresenter {
void validateCredentials(User user);
void onDestroy();
}复制代码
登陆的Presenter 的接口, 实现类为LoginPresenterImpl, 完成登陆的验证, 以及销
毁当前view。
public class LoginPresenterImpl implements LoginPresenter, OnLoginFinishedListener {
private LoginView loginView;
private LoginModel loginModel;
public LoginPresenterImpl(LoginView loginView) {
this.loginView = loginView;
loginModel = new LoginModelImpl();
}
@Override
public void validateCredentials(User user) {
if (loginView != null) {
loginView.showProgress();
}
if (loginModel != null) {
loginModel.login(user, this);
}
}
@Override
public void onDestroy() {
loginView = null;
}
@Override
public void usernameError(int errorCode) {
if (loginView != null) {
loginView.hideProgress();
loginView.setuserNameError(errorCode);
}
}
@Override
public void passwordError(int errorCode) {
if (loginView != null) {
loginView.hideProgress();
loginView.setpassWordError(errorCode);
}
}
@Override
public void sucess() {
if (loginView != null) {
loginView.onSuccess();
}
} 复制代码
}