专业的编程技术博客社区

网站首页 > 博客文章 正文

使用Kotlin实战一个BaseActivity并制作一个登录页

baijin 2024-09-10 11:00:11 博客文章 6 ℃ 0 评论

一、内容提要

在正常的Android项目开发过程中,会用到许多公共的部分。例如:自己封装或总结的基础类库以及Base*相关的内容,如BaseActivity、BaseApplication等。子类通过继承Base类可以继承父类的一些公用的特性以及行为。例如:接下来我们要介绍的BaseActivity就统一封装了导航栏(ActionBar)以及统一的布局容器,子类Activity通过继承BaseActiivty直接集成ActionBar无需自己写公共布局,只需要集中精力写子Activity的个性化布局即可。下面通过实战来说说具体应该怎样干。

ps:今天还会说到封装框架比较常用的一个设计模式:模板方法模式

二、实战部分



相关类及布局文件介绍:

1.BaseActivity.kt 所有Activity的父类,其继承自FragmentActivity

2.base_layout.xml 其是BaseActivity的布局文件

3.LoginActivity.kt 登录页面Activity,其继承BaseActivity

4.login_layout.xml 登录页面的布局文件

  • BaseActivity.kt
/**
 * 所有Activity的基类
 * 此处定义一个抽象类
 * create by yangwei
 * on 2020/7/21 16:11
 */
abstract class BaseActivity : FragmentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.base_layout)
        //将子布局添加到容器
        //此处的getLayoutId()的初始化会延迟的子类,即LoginActivity中
      	//此处用到的实际模式是模板方法模式(下文会讲到这个模式)
        fl_content.addView(LayoutInflater.from(this).inflate(getLayoutId(), null))
      	//initViews()方法也是在BaseActivity中延时加载,其在子类中取代了onCreate的位置
      	//子类中的初始化都需要在这个方法中进行。
        initViews()
    }
		
    /**
     * 获取左边ImageView
     */
    fun getLeftIcon(): ImageView {
      //有些大致了解过android开发的小伙伴可能观察到了,在BaseActiivty中我们并没有对控件
      //进行初始化,但是我们用的时候却可以使用?这要得益于google提供的插件,ktx,只要我们的
      //build.gradle中引入了就无需进行findViewById就可以得到控件实例。其基本上完全取代了
      //ButterKnife的地位,对缩减Android的代码量非常有帮助
        return action_left_icon
    }

    /**
     * 设置左边图标资源
     */
    fun setLeftIcon(icon: Int) {
        action_left_icon.setImageResource(icon)
    }

    /**
     * 获取左边TextView
     */
    fun getLeftText(): TextView {
        return action_left_text
    }

    /**
     * 设置左边文本
     */
    fun setLeftText(value: String) {
      	//我们如何给一个value设置默认值呢?如果再java中我们可以想到的方案是三元运算符,但是在kotlin
      	//中我们只需要使用?:后面加内容即可,语法上确实简介了些。主要是kotlin的语法糖比java要
      //多一些
        action_left_text.text = value ?: ""
    }

    /**
     * 获取标题TextView
     */
    fun getCenterText(): TextView {
        return action_center_text
    }

    /**
     * 设置标题
     */
    fun setCenterText(value: String) {
      //给TextView设置text的时候,java是通过setText来设置的,而kotlin为了兼容java也可以
      //使用setText,但是ide会推荐你直接使用text属性,就像下面的代码一样。
        action_center_text.text = value
    }

    /**
     * 获取右边ImageView
     */
    fun getRightIcon(): ImageView {
        return action_right_icon
    }

    /**
     * 设置右边图标资源
     */
    fun setRightIcon(icon: Int) {
        action_right_icon.setImageResource(icon)
    }

    /**
     * 获取右边TextView
     */
    fun getRightText(): TextView {
        return action_right_text
    }

    /**
     * 设置右边文案
     */
    fun setRightText(value: String) {
        action_right_text.text = value
    }

    /**
     * 控制左边按钮的显示隐藏
     */
    fun visibleLeftLayout(bool: Boolean) {
        if (bool) action_left_linear.visibility = View.VISIBLE else action_left_linear.visibility =
            View.INVISIBLE
    }

    /**
     * 控制右边的按钮的显示隐藏
     */
    fun visibleRightLayout(bool: Boolean) {
      	//这里注意一下kotlin中的if else和java中的不一样,kotlin中的if else是表达式形式的
      //它的作用不仅仅条件语句,还可以是表达式,这个后面项目中遇到了详细介绍下
        if (bool) action_right_linear.visibility =
            View.VISIBLE else action_right_linear.visibility =
            View.INVISIBLE
    }

    /**
     * 初始化View,延时到子类中进行初始化,使用的模板方法模式
     */
    abstract fun initViews()

    /**
     * 获取布局的Id
     */
    abstract fun getLayoutId(): Int
}  

2.base_layout.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"
    android:orientation="vertical">
    <!--actionbar-->
    <include layout="@layout/actionbar_layout" />
    <!--  承载子布局的容器  -->
    <!--此容器承载的是子类的布局,父类布局把样式定义好,子类只用管自己的布局就行了-->
    <FrameLayout
        android:id="@+id/fl_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
<?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="50dp">
    <!--        左边图标和文案-->
    <LinearLayout
        android:id="@+id/action_left_linear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginStart="20dp"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/action_left_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/action_left_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/color_333333"
            android:layout_marginStart="5dp"
            android:textSize="16sp" />
    </LinearLayout>
    <!--        中间标题部分-->
    <TextView
        android:id="@+id/action_center_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textColor="@color/color_333333"
        android:textSize="18sp" />
    <!--        右边图标和文案-->
    <LinearLayout
        android:id="@+id/action_right_linear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginEnd="20dp"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/action_right_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/action_right_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="5dp"
            android:textColor="@color/color_333333"
            android:textSize="16sp" />
    </LinearLayout>
</RelativeLayout>

3.LoginActivity.kt

/**
 * 登录页面,集成BaseActivity
 * create by yangwei
 * on 2020/7/21 16:37
 */
class LoginActivity : BaseActivity() {
    //初始化子布局
    override fun getLayoutId(): Int {
        return R.layout.login_layout
    }
    //初始化View
    override fun initViews() {
        setCenterText("登录")
        login_btn_submit.setOnClickListener {
            if (checkInput()) {
                val intent: Intent = Intent()
                intent.setClass(LoginActivity@ this, MainActivity::class.java)
                startActivity(intent)
            }
        }
    }
		//这里重点说一下kotlin的函数,在kotlin中函数的定义为:func 函数名():返回值
  	//kotlin中定义函数的关键字是fun,其返回值类型的定义位置和java正好相反,它是在方法最后
  	//定义的。而且在kotlin中函数是头等公民,而且支持高阶函数。而java是在1.8以后开始支持函数式
  	//接口,高阶函数也是通过函数接口来完成的。这些东西在后面实战的时候再一一讲解吧
    private fun checkInput(): Boolean {
      	//此处利用string字符串的isNullOrEmpty来判断非空,可以说是类库封装的语法糖
      	//除此之外还有isNull,isEmpty等方法,大家可以私下去尝试下,这里就不一一演示了
        if (login_et_username.text.isNullOrEmpty()) {
            Toast.makeText(this, "用户名不能为空", Toast.LENGTH_LONG).show()
            return false
        }
        if (login_et_password.text.isNullOrEmpty()) {
            Toast.makeText(this, "密码不能为空", Toast.LENGTH_LONG).show()
            return false
        }
        return true
    }
}



4.login_layout.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">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:orientation="vertical">
        <!--用户名-->
        <EditText
            android:id="@+id/login_et_username"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_marginStart="50dp"
            android:layout_marginEnd="50dp"
            android:background="@color/light_white"
            android:hint="请输入用户名"
            android:inputType="text"
            android:maxLength="16"
            android:paddingStart="3dp" />
        <!--密码-->
        <EditText
            android:id="@+id/login_et_password"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_marginStart="50dp"
            android:layout_marginTop="20dp"
            android:layout_marginEnd="50dp"
            android:background="@color/light_white"
            android:hint="请输入密码"
            android:inputType="textPassword"
            android:maxLength="16"
            android:paddingStart="3dp" />
        <!--登录按钮-->
        <Button
            android:id="@+id/login_btn_submit"
            android:layout_width="match_parent"
            android:layout_height="47dp"
            android:layout_marginStart="50dp"
            android:layout_marginTop="30dp"
            android:layout_marginEnd="50dp"
            android:background="@color/theme"
            android:text="登录"
            android:textColor="@color/white"
            android:textSize="18sp" />
    </LinearLayout>
</RelativeLayout>



三、注意事项

以上就是通过定义一个BaseActivity并让LoginActivity集成的全部过程。这个BaseActivity主要就是解决一个问题,给子类布局提供一个规范。而这个规范是通过模板方法模式来实现的。

模板方法模式:定义一个算法中的操作框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤

此处的BaseActivity就是定义算法框架的,而延迟到子类中实现的步骤是initViews()和getLayoutId()两个方法。

四、结束语

以上就是今天的全部内容了,代码光看是不行的,各位同学可以参照例子手动写一写,可以加深一些印象。

下一节会通过kotlin实现一个底部导航栏:主页、车、我的。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表