使用Kotlin开发App快速高效,最直接的一个感受就是你的代码量减少了很多。这里写了一个小例,效果如下:
这个界面总体布局是:根布局是CoordinatorLayout,然后上部分是AppBarLayout,下部是ViewPager管理的Fragment。下面直接上代码,根据代码说明相关情况。
- CoordinatorActivity.kt文件
import kotlinx.android.synthetic.main.activity_coordinator.*
class CoordinatorActivity : FragmentActivity() {
private lateinit var mFragments: MutableList<Fragment>
private var mTitles = arrayOf("主页", "微博", "相册")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_coordinator)
setupViewPager()
}
private fun setupViewPager() {
mFragments = ArrayList<Fragment>()
// for (i in mTitles.indices) {
// val listFragment = ListFragment.newInstance(mTitles[i])
// mFragments.add(listFragment)
// }
mTitles.map {
val listFragment = ListFragment.newInstance(it)
mFragments.add(listFragment)
}
// 为ViewPager设置适配器
val adapter = ContentPagerAdapter(mFragments, mTitles)
viewpager.adapter = adapter
// 第三步:将ViewPager与TableLayout 绑定在一起
tabLayout.setupWithViewPager(viewpager)
}
internal inner class ContentPagerAdapter(val tabFragments: List<Fragment>, val tabIndicators: Array<String>)
: FragmentPagerAdapter(supportFragmentManager) {
override fun getItem(position: Int): Fragment {
return tabFragments[position]
}
override fun getCount(): Int {
return tabIndicators.size
}
override fun getPageTitle(position: Int): CharSequence {
return tabIndicators[position]
}
}
}
一般贴代码我会省略导入文件,这里我特意贴出一条import信息,这是kotlin对android的一个功能扩展。使得我们不用再去写那么多findViewById了。
- ListFragment.kt文件
import kotlinx.android.synthetic.main.fragment_list.*
class ListFragment(override val layoutId: Int) : BaseFragment() {
private var mRecyclerView: RecyclerView? = null
private var title:String? = "测试"
private var mDatas: MutableList<String> = ArrayList()
private var mAdapter: MyAdapter? = null
// private var mSwipeRefreshLayout: SwipeRefreshLayout? = null
override fun initView(view: View?) {
}
//这里使用kotlin-android-extensions, 防止view为空,所以放在onViewCreated方法中
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val arguments = arguments //property access syntax
title = arguments?.getString(KEY)
val layoutManager = LinearLayoutManager(mContext)
recyclerView!!.layoutManager = layoutManager
(0..49).map {
var s = String.format("我是第%d个" + title, it)
mDatas.add(s)
}
// for (i in 0..49) {
// val s = String.format("我是第%d个" + title, i)
// mDatas.add(s)
// }
mAdapter = MyAdapter(mContext, mDatas)
recyclerView!!.adapter = mAdapter
swipeRefreshLayout!!.setOnRefreshListener {
swipeRefreshLayout!!.postDelayed({
swipeRefreshLayout!!.isRefreshing = false
Toast.makeText(mContext, "刷新完成", Toast.LENGTH_SHORT).show()
}, 1200)
}
}
fun tooglePager(isOpen: Boolean) {
if (isOpen) {
setRefreshEnable(false)
scrollToFirst(false)
} else {
setRefreshEnable(true)
}
}
fun scrollToFirst(isSmooth: Boolean) {
if (isSmooth) {
mRecyclerView?.smoothScrollToPosition(0)
} else {
mRecyclerView?.scrollToPosition(0)
}
}
fun setRefreshEnable(enabled: Boolean) {
swipeRefreshLayout!!.isEnabled = enabled
}
// override fun getLayoutId(): Int {
// return R.layout.fragment_list
// }
override fun fetchData() {
}
companion object {
private val KEY = "key"
fun newInstance(title: String): ListFragment {
val fragment = ListFragment(R.layout.fragment_list)
val bundle = Bundle()
bundle.putString(KEY, title)
fragment.arguments = bundle
return fragment
}
}
}
Fragment中我们也可以使用Kotlin针对Android的扩展功能,但是我们要获取布局文件中的View时不能在onCreateView方法中来获取,否则会抛出异常,因为在这个方法中获取不到,需要在onViewCreated方法中执行相关操作。
- BaseFragment.kt文件
abstract class BaseFragment : Fragment() {
protected var mView: View? = null
/**
* 表示View是否被初始化
*/
protected var isViewInitiated: Boolean = false
/**
* 表示对用户是否可见
*/
protected var isVisibleToUser: Boolean = false
/**
* 表示数据是否初始化
*/
protected var isDataInitiated: Boolean = false
protected lateinit var mContext: Context
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
if (mView == null) {
mContext = context
mView = View.inflate(mContext, layoutId, null)
initView(mView)
} else {
// 缓存的rootView需要判断是否已经被加过parent,如果有parent需要从parent删除,
// 要不然会发生这个rootview已经有parent的错误。
//Note that despite the fact that the right-hand side of as? is a non-null type String the result of the cast is nullable.
val parent = mView?.parent as ViewGroup?
parent?.removeView(mView)
}
return mView
}
protected abstract open fun initView(view: View?)
protected abstract val layoutId: Int
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
isViewInitiated = true
initListener()
initData()
prepareFetchData()
}
protected fun initListener() {}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
this.isVisibleToUser = isVisibleToUser
prepareFetchData()
}
abstract fun fetchData()
/***
* @param forceUpdate 表示是否在界面可见的时候是否强制刷新数据
* *
* @return
*/
@JvmOverloads fun prepareFetchData(forceUpdate: Boolean = false): Boolean {
if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) {
// 界面可见的时候再去加载数据
fetchData()
isDataInitiated = true
return true
}
return false
}
override fun onDestroyView() {
super.onDestroyView()
}
protected fun initData() {}
}
@JvmOverloads是对应有默认参数的情况,相对Java会生成多个重载方法。
- MyAdapter.kt文件
class MyAdapter(private val context: Context, private val datas: List<String>) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = View.inflate(context, R.layout.data_recycler, null)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.setIsRecyclable(false) // itemView是否重用
holder.item.text = datas[position]
}
override fun getItemCount(): Int {
return datas.size
}
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var item: TextView = itemView.findViewById(R.id.tv_item) as TextView
}
}
至此,这个界面效果就完成了。如果你用Java实现一遍的话,再对比一下代码量会发现kotlin简洁很多。
项目Github地址,仅供参考学习。