基类抽取:
在上一次https://www.cnblogs.com/webor2006/p/12612286.html搭建了项目的基本框架,接下来则继续往上磊代码了,先来创建一个每个项目都必有的BaseActivity,这里跟Java的Android差不多的就不多解释了,重点是解释Kotlin相关的:
package com.kotlin.musicplayer.base import android.os.Bundle import androidx.appcompat.app.AppCompatActivity /** * Activity抽象基类 */ abstract class BaseActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(getLayoutId()) initListeners() initData() } protected fun initData() { } protected fun initListeners() { } protected abstract fun getLayoutId(): Int }
其本上写法跟传统的Java差不多,再加上IDE的智能提示,写起来貌似没感到跟Java有太大的区别,之后遇到区别时再解释,对于Toast和Log的输出可以将其也封装到这个Base里,此时anko库就派上用场了,先看一下Toast的用法:
直接调用不就好了,干嘛还要封装一下?因为没有处理线程的问题,所以下面先封装一下它:
这里有个Kotlin的语法来了:
具体原因可以参考:https://www.cnblogs.com/webor2006/p/11498842.html,Kotlin语法规则有一条是这样说的:
而回到咱们这个方法的定义来看:
所以就符合这条规则了,另外看一下这个toast的具体实现:
这里函数的定义又涉及到好几个Kotlin的语法了:它是Context类中的一个扩展方法:
另外这种直接将方法的使用用=号相连是个啥语法呢?
另外这里还用了一个关键字:
它叫内联函数,可以参考https://www.cnblogs.com/webor2006/p/11518592.html:
也就是我们在调用内联函数时,并非单纯的函数调用,而是将被调用函数的代码直接嵌在了我们调用处。好接下来再来封装一下BaseFragment:
package com.kotlin.musicplayer.base import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import org.jetbrains.anko.runOnUiThread import org.jetbrains.anko.toast /** * Fragment基类 */ abstract class BaseFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initData(); } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return initView() } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) initListeners() initData() } protected fun initData() { } protected fun initListeners() { } protected fun showToast(msg: String) { context?.runOnUiThread { toast(msg) } } protected abstract fun initView(): View? }
欢迎界面:
有了基础Activity的封装之后,下面则来首先实现Splash页面,先来回顾一下效果:
其背景图如下:
package com.kotlin.musicplayer.ui.activity import com.kotlin.musicplayer.R import com.kotlin.musicplayer.base.BaseActivity class SplashActivity : BaseActivity() { override fun getLayoutId(): Int { return R.layout.activity_splash } }
<?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"> <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@mipmap/default_splash_bg" /> </LinearLayout>
此时运行看一下:
此时含有状态栏,得将其隐藏掉,所以得定义个全屏的主题:
接下来需要处理动画效果,其实就是让图片先放大一下,然后之后将其缩小成正常大小就可以了,比较简单,默认先在定义图片时将其放大一下:
接下来则需要处理缩小动画,此时需要覆写一下父类的initData()方法:
发现在子类中覆写不了,这时Kotlin的语法就又出来了,在之前也提及过,可以参考https://www.cnblogs.com/webor2006/p/11203903.html,其实要想让子类覆写,必须加个open关键字:
接下来则需要跳到MainActivity了,这里跳转依然可以使用anko库,能大大简化调用代码,使用方式如:
所以咱们使用一下:
此时运行看一下效果:
抽取startactivityandfinish:
对于这句代码可能未来也有需要调用:
所以可以将其提到父类中进行封装一下:
很明显这个抽取是有问题的:
关于泛型这块可以参考:https://www.cnblogs.com/webor2006/p/11296775.html,这里来修改一下:
此时就需要看一下startActivity这个函数的泛型定义了:
这里先不管这么多,先来校仿着定义一下:
果真是可以了,下面咱们来调用一下:
那么对于reified关健字的作用,可以参考博主:https://www.jianshu.com/p/bbe694b2c0a8,其实也就是要想通过泛型来获取到对应的class就必须加这个关键字,下面咱们举个例子:
此时就需要使用reified修饰并变成内联函数才行:
主界面布局:
接下来则来编写主界面了,它的效果长这样:
这里先来搭建一下界面框架,具体逻辑之后再慢慢实现,首先准备布局文件:
<?xml version="1.0" encoding="utf-8"?> <androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/colorPrimary" android:orientation="vertical" app:titleTextColor="#fff" />
activity_main.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"> <include layout="@layout/toolbar" /> <FrameLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> </LinearLayout>
接下来则需要定义底部Tab了,这里使用一个三方的库:https://github.com/roughike/BottomBar:
<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen> <tab icon="@mipmap/ic_bottom_home_icon" id="@+id/tab_home" title="首页" /> <tab icon="@mipmap/ic_bottom_mv_unselect" id="@+id/tab_mv" title="MV" /> <tab icon="@mipmap/ic_bottom_vlist_unselect" id="@+id/tab_vbang" title="V榜" /> <tab icon="@mipmap/ic_bottom_mvlist_unselect" id="@+id/tab_yuedan" title="悦单" /> </PreferenceScreen>
上面的文本直接写在xml中而木有提至strings.xml了,因为是一个练习项目,重点是操练kotlin,这些细节就暂且忽略上,其中涉及到四张小icon,按顺序今次为:
此时运行看一下整体效果:
呃,底部的图标也太大了点吧,跟预期效果相差很多,这里其实就是要针对不同分辨率文件夹弄几套对应的图就可以了,如下:
具体就不多说了,最后再运行:
好,今天Kotlin的项目实战先到这,水滴石穿~~