介绍框架XUI
一个简洁而又优雅的Android原生UI框架,源码地址以及作者教程如下:https://gitee.com/xuexiangjys/XUI
框架永远都是巨好用,不用设计界面,不用关注细枝末节,专注于逻辑开发便可。但是正如人生你每每追求的喜欢的往往会成为你的桎梏,框架也有它的不足,体现在开发过程中你会发现你想添加一个新功能是那么不容易,你用的很方便,这是作者所追求的,你想创新?come on老弟,有这本事我估计你不需要用这个框架。
话虽如此,XUI能满足你百分之90的需求,作为基础开发完全够用了。它提供了一整套的UI,提供了UIDemo,随用随取,美滴很。
框架将activity划分成了fragement,使控件通过fragement独立的调用,令我们的开发更加轻便。
LoginActivity.java
**
* 登录页面
*
* @author xuexiang
* @since 2019-11-17 22:21
*/
public class LoginActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
openPage(LoginFragment.class, getIntent().getExtras());
}
@Override
protected boolean isSupportSlideBack() {//是否支持侧滑返回
return false;
}
@Override
protected void initStatusBarStyle() {//初始化状态栏的样式
StatusBarUtils.initStatusBarStyle(this, false, Colors.WHITE);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {//如果fragment中处理了则fragment处理否则activity处理
return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event);
}
}
继承了封装好的基础activity,主要业务逻辑在LoginFragment.class中。
LoginFragment.java
/**
* 登录页面
*
* @author xuexiang
* @since 2019-11-17 22:15
*/
@Page(anim = CoreAnim.none)
public class LoginFragment extends BaseFragment {
@BindView(R.id.log_name)
MaterialEditText loginNameEt;
@BindView(R.id.log_pwd)
MaterialEditText loginPwdEt;
// @BindView(R.id.btn_get_verify_code)
// RoundButton btnGetVerifyCode;
private LoginHandler mLoginsHandler = new LoginHandler();;
private CountDownButtonHelper mCountDownHelper;
@Override
protected int getLayoutId() {
return R.layout.fragment_login;
}
@Override
protected TitleBar initTitle() {
TitleBar titleBar = super.initTitle()
.setImmersive(true);
titleBar.setBackgroundColor(Color.TRANSPARENT);
titleBar.setTitle("");
titleBar.setLeftImageDrawable(ResUtils.getVectorDrawable(getContext(), R.drawable.ic_login_close));
titleBar.setActionTextColor(ThemeUtils.resolveColor(getContext(), R.attr.colorAccent));
titleBar.addAction(new TitleBar.TextAction("") {
@Override
public void performAction(View view) {
onLoginSuccess();
}
});
return titleBar;
}
@Override
protected void initViews() {
// mCountDownHelper = new CountDownButtonHelper(btnGetVerifyCode, 60);
//隐私政策弹窗
if (!SettingUtils.isAgreePrivacy()) {
Utils.showPrivacyDialog(getContext(), (dialog, which) -> {
dialog.dismiss();
SettingUtils.setIsAgreePrivacy(true);
});
}
}
@SingleClick
@OnClick({R.id.loginBtn,R.id.regTv, R.id.tv_forget_password, R.id.tv_user_protocol, R.id.tv_privacy_protocol})
public void onViewClicked(View view) {
switch (view.getId()) {
// case R.id.btn_get_verify_code:
// if (etPhoneNumber.validate()) {
// getVerifyCode(etPhoneNumber.getEditValue());
// }
// break;
case R.id.loginBtn:
// if (loginNameEt.validate()) {
// if (loginPwdEt.validate()) {
loginByVerifyCode(loginNameEt.getEditValue(), loginPwdEt.getEditValue());
// }
// }
break;
case R.id.regTv:
ActivityUtils.startActivity(RegActivity.class);
break;
case R.id.tv_forget_password:
XToastUtils.info("忘记密码");
break;
case R.id.tv_user_protocol:
XToastUtils.info("用户协议");
break;
case R.id.tv_privacy_protocol:
XToastUtils.info("隐私政策");
break;
default:
break;
}
}
/**
* 根据密码登录
*
* @param loginNameEt 学号
* @param loginPwdEt 密码
*/
private void loginByVerifyCode(String loginNameEt, String loginPwdEt) {
loginSys( loginNameEt, loginPwdEt);
}
//登录系统
public void loginSys(String loginNameEt, String loginPwdEt){
System.out.println("进入loginSys(String loginNameEt, String loginPwdEt)");
// String username = loginNameEt.getText().toString().trim();
// String pwd = loginPwdEt.getText().toString().trim();
String username =loginNameEt;
String pwd = loginPwdEt;
ContentValues values = new ContentValues();
values.put("uId",username);
values.put("uPassword",pwd);
if(TextUtils.isEmpty(username) || TextUtils.isEmpty(pwd)){
//ToastUtils.info("注册");
System.out.println("用户名和密码不能为空");
Toast.makeText(getContext(),"用户名和密码不能为空",Toast.LENGTH_SHORT).show();
}else {
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("uId", username)
.add("uPassword",pwd)
.build();
Request request = new Request.Builder()
.url(ItFxqConstants.LOGIN_URL)
.post(requestBody).build();
Call call = okHttpClient.newCall(request);
// 开启异步线程访问网络
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
String res = response.body().string();
Message msg = new Message();
msg.what = ItFxqConstants.OK_STATUS;
msg.obj = res;
mLoginsHandler.sendMessage(msg);
}
@Override
public void onFailure(Call call, IOException e) {
}
});
}
}
class LoginHandler extends Handler {
@Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
switch (msg.what) {
case ItFxqConstants.OK_STATUS:
//解析获取的JSON数据
Gson gson = new Gson();
//通过反射得到type对象
Type listType = new TypeToken<Map>() {
}.getType();
Map resultMap = gson.fromJson((String)msg.obj, listType);
Boolean isSuccess = (Boolean)resultMap.get("isSuccess");
if(isSuccess){
//存储登录用户信息
Map userMap = (Map)resultMap.get("user");
System.out.println("userMap"+userMap.toString());
CommonUtils.storeLoginUser(userMap,LoginFragment.super.getContext());
// CommonUtils.navigateTo(this.getA,HomeActivity.class);
ActivityUtils.startActivity(MainActivity.class);
}else{
String message = (String)resultMap.get("msg");
Toast.makeText(getContext(),message,Toast.LENGTH_SHORT).show();
}
break;
case ItFxqConstants.ERROR_STATUS:
// Toast.makeText(LoginActivity.this,"操作失败",Toast.LENGTH_SHORT).show();
break;
}
}
}
/**
* 登录成功的处理
*/
private void onLoginSuccess() {
// String token = RandomUtils.getRandomNumbersAndLetters(16);
// if (TokenUtils.handleLoginSuccess(token)) {
// popToBack();
// ActivityUtils.startActivity(MainActivity.class);
// }
}
@Override
public void onDestroyView() {
if (mCountDownHelper != null) {
mCountDownHelper.recycle();
}
super.onDestroyView();
}
}
代码是将自己的代码移植到了框架中,所以有一些框架原有代码只是注释没有删掉,也许不太简洁,但注释掉的部分称得上是一个小功能,留作学习。
在XUI中控件的绑定变得很简单,通过MyBatis将控件ID和定义连接。这都归功于作者在BaseFragment中的封装。
fragment_login.xml
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com)
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
-->
<LinearLayout 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"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_gravity="center_horizontal"
app:srcCompat="@drawable/ic_splash_app_logo_xui" />
<TextView
style="@style/TextStyle.Title"
android:layout_width="match_parent"
android:layout_marginTop="10dp"
android:text="登 录"
android:textSize="30sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="24dp"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:tint="?attr/colorAccent"
app:srcCompat="@drawable/ic_phone" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/log_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="36dp"
android:hint="请输入您的学号"
android:inputType="number"
app:met_clearButton="true"
app:met_errorMessage="无效的学号"
app:met_floatingLabel="normal"
app:met_floatingLabelText="学号"
app:met_regexp="" />
</FrameLayout>
<FrameLayout
android:id="@+id/fl_verify_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:tint="?attr/colorAccent"
app:srcCompat="@drawable/ic_password" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/log_pwd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="36dp"
android:hint="请输入密码"
android:inputType="textPassword"
app:met_clearButton="false"
app:met_errorMessage=""
app:met_floatingLabel="normal"
app:met_floatingLabelText="密码"
app:met_maxCharacters="11"
app:met_regexp="" />
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.xuexiang.xui.widget.alpha.XUIAlphaTextView
android:id="@+id/regTv"
style="@style/TextStyle.Explain"
android:layout_gravity="start"
android:paddingStart="10dp"
android:paddingTop="5dp"
android:paddingEnd="10dp"
android:paddingBottom="5dp"
android:text="注册用户"
android:textColor="@color/xui_config_color_primary_text" />
<com.xuexiang.xui.widget.alpha.XUIAlphaTextView
android:id="@+id/tv_forget_password"
style="@style/TextStyle.Explain"
android:layout_gravity="end"
android:paddingStart="10dp"
android:paddingTop="5dp"
android:paddingEnd="10dp"
android:paddingBottom="5dp"
android:text="忘记密码"
android:textColor="@color/xui_config_color_primary_text" />
</FrameLayout>
</LinearLayout>
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/loginBtn"
style="@style/SuperButton.Primary.Login"
android:layout_marginTop="16dp"
android:text="登录"
/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginBottom="20dp"
android:gravity="center_horizontal"
android:orientation="horizontal">
<TextView
style="@style/TextStyle.Explain"
android:layout_width="wrap_content"
android:text="登陆/注册代表您已阅读并同意"
android:textColor="@color/xui_config_color_primary_text" />
<com.xuexiang.xui.widget.alpha.XUIAlphaTextView
android:id="@+id/tv_user_protocol"
style="@style/TextStyle.Explain"
android:layout_width="wrap_content"
android:text="用户协议"
android:textColor="?attr/colorAccent" />
<TextView
style="@style/TextStyle.Explain"
android:layout_width="wrap_content"
android:text="和"
android:textColor="@color/xui_config_color_primary_text" />
<com.xuexiang.xui.widget.alpha.XUIAlphaTextView
android:id="@+id/tv_privacy_protocol"
style="@style/TextStyle.Explain"
android:layout_width="wrap_content"
android:text="隐私政策"
android:textColor="?attr/colorAccent" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
控件带有校验功能, 属性app:met_regexp=“正则表达式” 。相应的属性还有错误信息、最大字数限制等。
后记:前两篇都是前台的搭建,其中最为重要的当属网络请求的发送和接收。一个重要的贯穿整个项目的重点。