一、前言:
这个程序中使用了我之前学的一部分知识,算是一个小总结吧,首先是登录界面的实现,这个还是比较简单的,主要是在布局文件中将用到的控件按预想的界面排放,在代码中按下登录按钮后通过获得输入的账号和密码和设置的正确密码比对,如果正确就跳到主界面去。广播实现强制下线的话稍微麻烦一些,收到强制下线广播后,弹出AlertDialog对话框提示用户,当用户在AlertDialog提示被强制下线对话框确认后,就要关闭所有的Activity并且跳转到登录界面去。最后就是自定义清除按钮的EditText了,其实这个我是用的别人的代码,具体是哪位大佬的我也忘了这里就不说了。下面看看具体实现的功能和实现代码吧。
二、程序效果图:
1. 登录界面和自定义EditText
2. 登录成功后强制下线
三、实现代码:
1.新建一个工程,默认的Activity命名为LoginActivity作为登录界面,这样程序启动界面就是登录界面了,不用再ActivityMainfest里面改。新建一个BaseActivity和ActivityCollector,代码如下:
public class BaseActivity extends AppCompatActivity {
private ForceOfflineReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate ( savedInstanceState );
ActivityCollector.addActivity ( this );
}
@Override
protected void onResume() {
super.onResume ();
//注册广播接收器
IntentFilter intentFilter = new IntentFilter ( );
intentFilter.addAction ( "com.example.lyp.broadcastpractice.FORCE_OFFLINE" );
receiver = new ForceOfflineReceiver ();
registerReceiver (receiver,intentFilter );
}
//取消广播接收器的注册
@Override
protected void onPause() {
super.onPause ();
if(receiver!=null){
unregisterReceiver ( receiver );
receiver = null;
}
}
@Override
protected void onDestroy(){
super.onDestroy ();
ActivityCollector.removeActivity ( this );
}
class ForceOfflineReceiver extends BroadcastReceiver{
@Override
public void onReceive(final Context context, Intent intent) {
//弹出一个提醒被强制下线的对话框
AlertDialog.Builder builder = new AlertDialog.Builder ( context );
builder.setTitle ( "强制下线通知" );
builder.setMessage ( "你的账号在别处登录,你已被强制下线。请重新登录!" );
builder.setCancelable ( false );
builder.setPositiveButton ( "确认", new DialogInterface.OnClickListener () {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
ActivityCollector.finishAll ();//销毁所有Activity
Intent intent = new Intent ( context,LoginActivity.class );
context.startActivity ( intent );
}
} );
builder.show ();
}
}
}
public class ActivityCollector {
public static List<Activity> activities = new ArrayList<> ( );
//添加一个Activity
public static void addActivity(Activity activity){
activities.add ( activity );
}
//删除一个Activity
public static void removeActivity(Activity activity){activities.remove ( activity );}
//销毁Activity列表里面所有的Activity
public static void finishAll(){
for(Activity activity:activities){
if(!activity.isFinishing ()){
activity.finish ();
}
}
activities.clear();
}
}
BaseActivity主要是就是让其他的Activity继承,然后注册广播接收器,并且实现在收到强制下线广播后弹出提示对话框,待用户点击确认后调用ActivityCollector中的finishAll函数销毁所有Activity。
2.然后就是自带删除按钮的EditText了,自定义代码如下:
public class ClearEditText extends android.support.v7.widget.AppCompatEditText implements View.OnFocusChangeListener, TextWatcher {
private Drawable mClearDrawable;
private boolean hasFocus;
public ClearEditText(Context context) {
this(context, null);
}
public ClearEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ClearEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
// getCompoundDrawables() Returns drawables for the left(0), top(1), right(2) and bottom(3)
mClearDrawable = getCompoundDrawables()[2]; // 获取drawableRight
if (mClearDrawable == null) {
// 如果为空,即没有设置drawableRight,则使用R.mipmap.close这张图片
mClearDrawable = getResources().getDrawable(R.drawable.clear);
}
mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());
setOnFocusChangeListener(this);
addTextChangedListener(this);
// 默认隐藏图标
setDrawableVisible(false);
}
/**
* 我们无法直接给EditText设置点击事件,只能通过按下的位置来模拟clear点击事件
* 当我们按下的位置在图标包括图标到控件右边的间距范围内均算有效
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (getCompoundDrawables()[2] != null) {
int start = getWidth() - getTotalPaddingRight() + getPaddingRight(); // 起始位置
int end = getWidth(); // 结束位置
boolean available = (event.getX() > start) && (event.getX() < end);
if (available) {
this.setText("");
}
}
}
return super.onTouchEvent(event);
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
this.hasFocus = hasFocus;
if (hasFocus && getText().length() > 0) {
setDrawableVisible(true); // 有焦点且有文字时显示图标
} else {
setDrawableVisible(false);
}
}
@Override
public void onTextChanged(CharSequence s, int start, int count, int after) {
if (hasFocus) {
setDrawableVisible(s.length() > 0);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
protected void setDrawableVisible(boolean visible) {
Drawable right = visible ? mClearDrawable : null;
setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], right, getCompoundDrawables()[3]);
}
}
这是一位大佬写的,我也看不太懂。所以就不做过多解释,其实里面还有一些其他的功能我都没用到,主要是用了在EditText末尾加一个删除按钮的功能。下面是清除按钮的图片clear.png:
3. 接下来就是登录界面了,这个Activity要继承自BaseActivity,代码如下:
public class LoginActivity extends BaseActivity {
private EditText mEt_phone;
private EditText mEt_password;
private Button mBt_login;
private String phone;
private String password;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate ( savedInstanceState );
setContentView ( R.layout.activity_login );
mBt_login = findViewById ( R.id.mBt_login );
mEt_phone = findViewById ( R.id.mEt_phone );
mEt_password = findViewById ( R.id.mEt_password );
mBt_login.setOnClickListener ( new View.OnClickListener () {
@Override
public void onClick(View view) {
phone = mEt_phone.getText ().toString ();
password = mEt_password.getText ().toString ();
if(phone.equals ( "admin" )&&password.equals ( "123456" )){
Intent intent = new Intent ( LoginActivity.this,MainActivity.class );
startActivity ( intent );
finish ();
}else {
Toast.makeText ( LoginActivity.this,
"账户或者密码错误",Toast.LENGTH_SHORT).show ();
}
}
} );
}
}
这个就简单多了,主要是在点击了登录按钮以后判断一下账号和密码是否正确,如果是就跳转到MainActivity中去。下面是它的布局问件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding ="10dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="账号:"
android:textSize="22sp"
/>
<com.example.lyp.broadcastpractice.ClearEditText
android:id="@+id/mEt_phone"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:hint="默认账号是admin"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="密码:"
android:textSize="22sp"
/>
<com.example.lyp.broadcastpractice.ClearEditText
android:id="@+id/mEt_password"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:inputType="textPassword"
android:maxLines="6"
android:hint="默认密码是123456"
/>
</LinearLayout>
<Button
android:id="@+id/mBt_login"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="登录"
android:textSize="18sp"/>
</LinearLayout>
其他没什么特别的,主要就是EditText要使用我们自定义的。其他属性和EditText是一样的。使用我们自定义的EditText的时候要用完整的包名索引,中间是他的属性设置,像下面这样:
<com.example.lyp.broadcastpractice.ClearEditText
.......
/>
4.最后就是登录成功后的主界面MainActivity了,这个Activity同样要继承自BaseActivity,代码如下:
public class MainActivity extends BaseActivity {
private Button mBt_error;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate ( savedInstanceState );
setContentView ( R.layout.activity_main );
mBt_error = findViewById ( R.id.mBt_error );
mBt_error.setOnClickListener ( new View.OnClickListener () {
@Override
public void onClick(View view) {
//发送下线广播
Intent intent = new Intent ("com.example.lyp.broadcastpractice.FORCE_OFFLINE");
sendBroadcast ( intent );
}
} );
}
}
它就更没什么特别的了,主要就是在按下按钮后发送一个强制下线的全局广播,用按钮模拟被强制下线。所以它的布局就只有一个Button:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="10dp"
>
<Button
android:id="@+id/mBt_error"
android:layout_width="150dp"
android:layout_height="60dp"
android:layout_gravity="center"
android:text="被逼下线"
android:textSize="18sp"
/>
</LinearLayout>
这样整个程序就完成了。回顾一下之前靴子的东西还是很有用的,应为这些东西学了不用很容易就忘了。学了之后最后做一些综合性的工程,巩固一下效果还是不错的。