使用kotlin编写第一个Android应用界面

使用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地址,仅供参考学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值