Kotlin实现Android Tab选项卡
740662426
8年前
<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>