Kotlin实现Android Tab选项卡

740662426 7年前
   <p>在之前两篇文章中,介绍了Android中网球请求的实现,那么本篇文章中,我们实现下现在APP中最通用的 <strong>Tabbar</strong> 的实现:</p>    <h3>Tabbar1.0</h3>    <p>以前的项目中 <strong>Tabbar</strong> 是使用 <strong>Gridview</strong> 实现,这里贴出部分代码:</p>    <p>首先定义一个 <strong>Tab</strong> 的model类:</p>    <pre>  <code class="language-java">open class Tab(var res: Int,   var selRes: Int, var name: String,  var tag:String,var f: Fragment) {}</code></pre>    <p>Activity中的布局 <strong>activity_home</strong> 为:</p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <android.support.design.widget.CoordinatorLayout          xmlns:android="http://schemas.android.com/apk/res/android"          android:layout_width="match_parent"          android:layout_height="match_parent"          android:fitsSystemWindows="true">      <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content">          <include layout="@layout/toolbar" android:id="@+id/tool"/>          <GridView android:background="@color/white" android:layout_alignParentBottom="true"                    android:numColumns="4" android:id="@+id/gridGv"                    android:layout_width="match_parent"                    android:layout_height="wrap_content"/>          <FrameLayout android:layout_below="@id/tool" android:layout_above="@id/gridGv"                       android:id="@+id/frameLayout" android:layout_width="match_parent"                       android:layout_height="match_parent"/>        </RelativeLayout>  </android.support.design.widget.CoordinatorLayout></code></pre>    <p>HomeActivity,其中当用户未登录时,则跳到 <strong>LoginActivity</strong></p>    <pre>  <code class="language-java">class HomeActivity : BaseActivity() {        internal var items = listOf(              Tab(R.mipmap.ic_home, R.mipmap.ic_home_sel, "首页", "index", HomeFragment.getInstance()),              Tab(R.mipmap.ic_product, R.mipmap.ic_product_sel, "产品", "product", ProductFragment.getInstance()),              Tab(R.mipmap.ic_cart, R.mipmap.ic_cart_sel, "购物车", "cart", CartFragment.getInstance()),              Tab(R.mipmap.ic_user, R.mipmap.ic_user_sel, "我的", "me", MeFragment.getInstance()))        var adapter: TabAdapter? = null      override fun onCreate(savedInstanceState: Bundle?) {          super.onCreate(savedInstanceState)          setContentView(R.layout.activity_home)          adapter = TabAdapter(this)            adapter!!.addAll(items)          gridGv.gravity = Gravity.CENTER          gridGv.selector = ColorDrawable(Color.TRANSPARENT)          toFragment(items[0].f, R.id.frameLayout)          gridGv.adapter = adapter          initTitle("首页")          gridGv.onItemClick { adapterView, view, i, l ->              if (items[i].tag.equals("me") && TextUtils.isEmpty(Preference.with(this).token) ) {                  startActivity<LoginActivity>()                  return@onItemClick              }              toFragment(items[i].f, R.id.frameLayout)              initTitle(items[i].name)              adapter?.pos = i              adapter?.notifyDataSetChanged()          }          adapter!!.notifyDataSetChanged()        }        fun toFragment(f: Fragment, id: Int) {          val transaction = fragmentManager.beginTransaction()          transaction.replace(id, f)          transaction.commit()      }    }</code></pre>    <p>TabAdapter</p>    <pre>  <code class="language-java">/**   * Created by vslimit on 16/1/15.   */  class TabAdapter(context: Context) : ArrayAdapter<Tab>(context, 0) {      val inflater = LayoutInflater.from(context)      var pos: Int = 0      override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {          val item = getItem(position)          val view = convertView ?: inflater.inflate(R.layout.item_tab_menu, parent, false)            val nameView = view.findViewById(R.id.item_text) as TextView          val imageView = view.findViewById(R.id.item_image) as ImageView            nameView.text = item.name          nameView.textColor = if (position == pos) context.resources.getColor(R.color.head_orange) else context.resources.getColor(R.color.product_name_black)          imageView.imageResource = if (position == pos) item.selRes else item.res            return view      }</code></pre>    <p>这样基于 <strong>Gridview</strong> 已经实现了,但是,考虑到 <strong>RecycleView</strong> 比较流行,于是在新的版本中,使用了 <strong>RecycleView</strong> 来实现,并对其中的部分实现进行了优化,下面我们来看 <strong>Tabbar2.0</strong></p>    <h3>Tabbar2.0</h3>    <p>Tab类是预定好的,并且是有序的,因此,采用 <strong>enum</strong> 来实现:</p>    <pre>  <code class="language-java">package com.vslimit.kotlindemo.model    import com.vslimit.kotlindemo.R  import com.vslimit.kotlindemo.fragment.BaseFragment  import com.vslimit.kotlindemo.fragment.MainFragment  import com.vslimit.kotlindemo.fragment.ProductFragment    /**   * Created by vslimit on 16/12/2.   */  enum class TabTagEnum (val text: String, val res: Int, val selRes: Int, val fragment: BaseFragment) {      HOME("首页", R.mipmap.ic_home, R.mipmap.ic_home_sel, MainFragment.getInstance()), PRODUCT("发现", R.mipmap.ic_product, R.mipmap.ic_product_sel, ProductFragment.getInstance()), CART("购物车", R.mipmap.ic_cart, R.mipmap.ic_cart_sel, MainFragment.getInstance()), ME("我的", R.mipmap.ic_user, R.mipmap.ic_user_sel, MainFragment.getInstance())  }</code></pre>    <p>Activity布局 <strong>activity_main</strong></p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"                  xmlns:tools="http://schemas.android.com/tools"                  android:layout_width="match_parent"                  android:layout_height="match_parent"                  tools:context=".activity.MainActivity">      <android.support.v7.widget.RecyclerView              android:id="@+id/tabRv"              android:layout_width="match_parent"              android:layout_height="49dp"              android:layout_alignParentBottom="true"              android:background="@android:color/white"/>      <View android:layout_width="match_parent" android:layout_height="1dp" android:layout_above="@id/tabRv" android:id="@+id/line" android:background="@android:color/black"/>      <FrameLayout android:layout_above="@id/line"                   android:id="@+id/frameLayout"                   android:layout_width="match_parent"                   android:layout_height="match_parent"/>  </RelativeLayout></code></pre>    <p>MainActivity之前使用 <strong>replace,remove</strong> 来进行 <strong>Fragment</strong> 的替换,但是,考虑到性能优化,改用 <strong>hide,show</strong> 的方式,可这样处理容易导致 <strong>fragment</strong> 重叠问题,这里使用了@YoKey 的文章中的方式进行处理<a href="/misc/goto?guid=4959728016569309375" rel="nofollow,noindex"> </a>。</p>    <pre>  <code class="language-java">package com.vslimit.kotlindemo.activity    import android.os.Bundle  import android.support.annotation.Nullable  import android.support.v4.app.Fragment  import android.support.v4.app.FragmentManager  import android.support.v4.app.FragmentTransaction  import android.support.v7.app.AppCompatActivity  import android.support.v7.widget.GridLayoutManager  import com.vslimit.kotlindemo.R  import com.vslimit.kotlindemo.model.TabTagEnum  import com.vslimit.kotlindemo.adapter.TabAdapter  import kotlinx.android.synthetic.main.activity_main.*  import org.jetbrains.anko.AnkoLogger  import org.jetbrains.anko.info    class MainActivity : AppCompatActivity(), AnkoLogger {        internal var items = TabTagEnum.values().asList()        var adapter: TabAdapter? = null        override fun onCreate(@Nullable savedInstanceState: Bundle?) {          super.onCreate(savedInstanceState)          setContentView(R.layout.activity_main)          if (savedInstanceState == null) {              initFragment(TabTagEnum.HOME.fragment)          }          val layoutManager: GridLayoutManager = GridLayoutManager(this, 4)          tabRv.layoutManager = layoutManager          adapter = TabAdapter(items) {              switchContent(items[adapter!!.pos].fragment, it.fragment)              adapter!!.pos = it.ordinal              adapter!!.notifyDataSetChanged()          }          tabRv.adapter = adapter          adapter!!.notifyDataSetChanged()          info("onCreate")      }        override fun onRestoreInstanceState(savedInstanceState: Bundle?) {          super.onRestoreInstanceState(savedInstanceState)          info("onRestoreInstanceState")      }        override fun onStart() {          super.onStart()          info("onStart")      }        override fun onResume() {          super.onResume()          info("onResume")      }        override fun onSaveInstanceState(outState: Bundle?) {          super.onSaveInstanceState(outState)          info("onSaveInstanceState")      }          override fun onPause() {          super.onPause()          info("onPause")      }        override fun onStop() {          super.onStop()          info("onStop")      }        override fun onDestroy() {          super.onDestroy()          info("onDestroy")      }        fun switchContent(from: Fragment, to: Fragment) {          val fm: FragmentManager = supportFragmentManager          //添加渐隐渐现的动画          val ft: FragmentTransaction = fm.beginTransaction()          if (!to.isAdded) {              // 先判断是否被add过              ft.hide(from).add(R.id.frameLayout, to) // 隐藏当前的fragment,add下一个到Activity中          } else {              ft.hide(from).show(to) // 隐藏当前的fragment,显示下一个          }          ft.commit()      }        fun initFragment(to: Fragment) {          val fm: FragmentManager = supportFragmentManager          //添加渐隐渐现的动画  //        val ft: FragmentTransaction = fm.beginTransaction()          fm.beginTransaction().add(R.id.frameLayout, to).commit()      }  }</code></pre>    <p>TabAdapter</p>    <pre>  <code class="language-java">package com.vslimit.kotlindemo.adapter    import android.support.v7.widget.RecyclerView  import android.view.View  import android.view.ViewGroup  import com.vslimit.kotlindemo.R  import com.vslimit.kotlindemo.extensions.ctx  import com.vslimit.kotlindemo.model.TabTagEnum  import kotlinx.android.synthetic.main.tab_item_menu.view.*  import org.jetbrains.anko.imageResource  import org.jetbrains.anko.layoutInflater  import org.jetbrains.anko.onClick    /**   * Created by vslimit on 16/12/2.   */  class TabAdapter(val items: List<TabTagEnum>, val itemClick: (TabTagEnum) -> Unit) : RecyclerView.Adapter<TabAdapter.ViewHolder>() {        var pos: Int = TabTagEnum.HOME.ordinal        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {          val view = parent.ctx.layoutInflater.inflate(R.layout.tab_item_menu, parent, false)          return ViewHolder(view, itemClick)      }        override fun onBindViewHolder(holder: ViewHolder, position: Int) {          holder.bindForecast(items[position], pos == position)      }        override fun getItemCount() = items.size        class ViewHolder(view: View, val itemClick: (TabTagEnum) -> Unit) : RecyclerView.ViewHolder(view) {            fun bindForecast(item: TabTagEnum, flag: Boolean) {              with(item) {                  itemView.item_image.imageResource = if (flag) item.selRes else item.res                  itemView.item_text.text = item.text                  itemView.onClick { itemClick(item) }              }          }      }    }</code></pre>    <p>至此,基于 <strong>RecycleView</strong> 的 <strong>Tabbar</strong> 已经实现,效果如图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/52a826febda3bad1f049009ce8ede23f.jpg"></p>    <p> </p>    <p> </p>    <p>来自:http://www.jianshu.com/p/c4c63e43bd00</p>    <p> </p>