基類抽取:
在上一次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的項目實戰先到這,水滴石穿~~