android TabLayout实现京东详情效果

Google在2015的IO大会上,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的Android Design Support Library,在这个support库里面,Google给我们提供了更加规范的MD设计风格的控件。最重要的是,Android Design Support Library的兼容性更广,直接可以向下兼容到Android 2.2。

这两天需要做一个仿京东详情的页面,上面的Tab切换,以前都是自己写Viewpager+fragment,或者Indicator的深度定制,一直想尝试一下TabLayout,于是就有了下面的坑。

然后下面是我简单的实现效果(个人觉得很坑,还不如自己自定义的导航器)

添加引用库

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. dependencies {  
  2.     compile fileTree(dir: 'libs', include: ['*.jar'])  
  3.     compile 'com.android.support:appcompat-v7:24.2.0'  
  4.     compile 'com.android.support:design:24.2.0'  
  5.     compile 'com.android.support:recyclerview-v7:24.2.0'  
  6.     compile 'com.android.support:cardview-v7:24.2.0'  
  7. }  

Toolbar与TabLayout

我们来看一下实现的布局:
[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. <pre code_snippet_id="1857898" snippet_file_name="blog_20160830_2_1741274" name="code" class="html"><?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:orientation="vertical">  
  7.   
  8.   
  9.     <LinearLayout  
  10.         android:layout_width="match_parent"  
  11.         android:layout_height="wrap_content"  
  12.         android:background="@color/c12"  
  13.         android:gravity="center_vertical"  
  14.         android:minHeight="45dp"  
  15.         android:orientation="horizontal"  
  16.         android:paddingLeft="15dp"  
  17.         android:paddingRight="15dp">  
  18.   
  19.         <ImageView  
  20.             android:id="@+id/back"  
  21.             android:layout_width="wrap_content"  
  22.             android:layout_height="wrap_content"  
  23.             android:background="@drawable/back_icon" />  
  24.   
  25.         <LinearLayout  
  26.             android:layout_width="0dp"  
  27.             android:layout_height="match_parent"  
  28.             android:layout_weight="1"  
  29.             android:orientation="horizontal">  
  30.   
  31.             <android.support.design.widget.TabLayout  
  32.                 android:id="@+id/tabLayout"  
  33.                 android:layout_width="match_parent"  
  34.                 android:layout_height="match_parent"  
  35.                 app:tabTextAppearance="@style/TabLayoutTextStyle"  
  36.                 app:tabGravity="center"  
  37.                 app:tabMode="fixed"  
  38.                 app:tabTextColor="@color/c7"  
  39.                 app:tabSelectedTextColor="@color/c8"/>  
  40.   
  41.         </LinearLayout>  
  42.   
  43.         <ImageView  
  44.             android:id="@+id/toolbar_more"  
  45.             android:layout_width="wrap_content"  
  46.             android:layout_height="wrap_content"  
  47.             android:layout_marginLeft="10dp"  
  48.             android:background="@drawable/more_icon" />  
  49.     </LinearLayout>  
  50.   
  51.     <View style="@style/horizontal_line" />  
  52.   
  53.     <android.support.v4.view.ViewPager  
  54.         android:id="@+id/viewPager"  
  55.         android:layout_width="match_parent"  
  56.         android:layout_height="0dp"  
  57.         android:layout_weight="1" />  
  58.   
  59.   
  60.     <View style="@style/horizontal_line" />  
  61.   
  62.     <LinearLayout  
  63.         android:layout_width="match_parent"  
  64.         android:layout_height="48dp"  
  65.         android:background="@color/c12"  
  66.         android:orientation="horizontal">  
  67.   
  68.         <LinearLayout  
  69.             android:layout_width="0dp"  
  70.             android:layout_height="match_parent"  
  71.             android:layout_weight="1">  
  72.   
  73.             <TextView  
  74.                 android:layout_width="0dp"  
  75.                 android:layout_height="match_parent"  
  76.                 android:layout_weight="1"  
  77.                 android:gravity="center"  
  78.                 android:text="收藏"  
  79.                 android:textSize="10sp" />  
  80.   
  81.             <View style="@style/vertical_line" />  
  82.   
  83.             <TextView  
  84.                 android:layout_width="0dp"  
  85.                 android:layout_height="match_parent"  
  86.                 android:layout_weight="1"  
  87.                 android:gravity="center"  
  88.                 android:text="购物车"  
  89.                 android:textSize="10sp" />  
  90.         </LinearLayout>  
  91.   
  92.         <LinearLayout  
  93.             android:layout_width="0dp"  
  94.             android:layout_height="match_parent"  
  95.             android:layout_weight="1.5"  
  96.             android:background="@color/c8"  
  97.             android:gravity="center">  
  98.   
  99.             <TextView  
  100.                 style="@style/style_c12_s16"  
  101.                 android:gravity="center"  
  102.                 android:text="加入购物车" />  
  103.         </LinearLayout>  
  104.     </LinearLayout>  
  105. </LinearLayout></pre><br><br>  

这布局文件最关键的一点就是android.support.design.widget.TabLayout 标签中的app:tabMode=”scrollable”,他设置tab的模式为“可滑动的”。
其他的用法和Indicator的用法差不多,都需要设置适配器,然后通过数据实现页面的适配。直接上代码
Adapter
[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:10px;">public class ProductDetailPagerAdapter extends FragmentPagerAdapter {  
  2.   
  3.     private List<FragmentmFragments=null;  
  4.     private List<StringmTitles=null;  
  5.   
  6.     public ProductDetailPagerAdapter(FragmentManager fm, List<Fragment> mFragments,List<String> mTitles) {  
  7.         super(fm);  
  8.         this.mFragments =mFragments;  
  9.         this.mTitles=mTitles;  
  10.     }  
  11.   
  12.     public ProductDetailPagerAdapter(FragmentManager fm, Fragment... fragments) {  
  13.         super(fm);  
  14.         this.mFragments = Arrays.asList(fragments);  
  15.     }  
  16.   
  17.     @Override  
  18.     public Fragment getItem(int position) {  
  19.         return mFragments.get(position);  
  20.     }  
  21.   
  22.     @Override  
  23.     public int getCount() {  
  24.         return mFragments.size();  
  25.     }  
  26.   
  27.     @Override  
  28.     public CharSequence getPageTitle(int position) {  
  29.         return mTitles.get(position);  
  30.     }  
  31. }</span>  


主页面的相关逻辑,这里的Fragment就是简单的Fragment。
[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. <pre code_snippet_id="1857898" snippet_file_name="blog_20160830_4_1152629" name="code" class="html">public class ProductDetailsActivity extends BaseActivity {  
  2.   
  3.     @BindView(R.id.viewPager)  
  4.     ViewPager viewPager;  
  5.     @BindView(R.id.toolbar_more)  
  6.     ImageView toolbarMore;  
  7.     @BindView(R.id.tabLayout)  
  8.     TabLayout tabLayout;  
  9.   
  10.     private List<Fragment> mFragments;  
  11.     private String[] titles = new String[]{"商品", "详情"};  
  12.     private ProductDetailPagerAdapter productPagerAdapter = null;  
  13.     private MorePopupWindow popupWindow = null;  
  14.   
  15.     @Override  
  16.     protected void onCreate(Bundle savedInstanceState) {  
  17.         super.onCreate(savedInstanceState);  
  18.         setContentView(R.layout.activity_product_details);  
  19.         ButterKnife.bind(this);  
  20.         init();  
  21.     }  
  22.   
  23.     private void init() {  
  24.         initViewPager();  
  25.     }  
  26.   
  27.     private void initViewPager() {  
  28.         mFragments = new ArrayList<>();  
  29.         mFragments.add(new ProductFragment());  
  30.         mFragments.add(new ProductDetailFragment());  
  31.   
  32.         productPagerAdapter = new ProductDetailPagerAdapter(getSupportFragmentManager(), mFragments, Arrays.asList(titles));  
  33.         viewPager.setOffscreenPageLimit(2);  
  34.         viewPager.setAdapter(productPagerAdapter);  
  35.         viewPager.setCurrentItem(1);  
  36.         tabLayout.setupWithViewPager(viewPager);  
  37.     }  
  38.   
  39.   
  40.     @OnClick(R.id.back)  
  41.     public void backClick() {  
  42.         finish();  
  43.     }  
  44.   
  45.     @OnClick(R.id.toolbar_more)  
  46.     public void moreClick() {  
  47.          
  48.     }  
  49.   
  50.     private AdapterView.OnItemClickListener onItemClickListener = new AdapterView.OnItemClickListener() {  
  51.         @Override  
  52.         public void onItemClick(AdapterView<?> parent, View view, int position,  
  53.                                 long id) {  
  54.             popupWindow.dismiss();  
  55.         }  
  56.     };  
  57.   
  58.   
  59.     public static void open(Context context) {  
  60.         Intent intent = new Intent(context, ProductDetailsActivity.class);  
  61.         context.startActivity(intent);  
  62.     }  
  63. }</pre><br><br>  
上面的代码都比较简单不做过多的解释,在使用TabLayout的时候需要注意一点:
tabmode有两个属性值:
MODE_FIXED:Fixed tabs display all tabs concurrently and are best used with content that benefits from quick pivots between tabs.
MODE_SCROLLABLE:Scrollable tabs display a subset of tabs at any given moment, and can contain longer tab labels and a larger number of tabs.
MODE_SCROLLABLE适合很多tabs的情况,是可以滚动的,如果你要实现京东的那种挤在一起的效果就需要MODE_FIXED了。
为了更好的满足开发需要,TabLayout实现了自定义TabLayout的样式,然后通过引入
[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. app:tabTextAppearance=""  
 

自定义icon添加到tab

当前的TabLayout没有方法让我们去添加icon,我们可以使用SpannableString结合ImageSpan来实现

[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. private int[] imageResId = {  
  2.         R.drawable.ic_one,  
  3.         R.drawable.ic_two,  
  4.         R.drawable.ic_three  
  5. };  
  6.    
  7. // ...  
  8.    
  9. @Override  
  10. public CharSequence getPageTitle(int position) {  
  11.     // Generate title based on item position  
  12.     // return tabTitles[position];  
  13.     Drawable image = context.getResources().getDrawable(imageResId[position]);  
  14.     image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());  
  15.     SpannableString sb = new SpannableString(" ");  
  16.     ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);  
  17.     sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);  
  18.     return sb;  
  19. }  

运行,发现没有显示,这是因为TabLayout创建的tab默认设置textAllCaps属性为true,这阻止了ImageSpan被渲染出来,可以通过下面的样式文件定义来改变:
[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. <style name="MyCustomTabLayout" parent="Widget.Design.TabLayout">  
  2.       <item name="tabTextAppearance">@style/MyCustomTextAppearance</item>  
  3. </style>  
  4.    
  5. <style name="MyCustomTextAppearance" parent="TextAppearance.Design.Tab">  
  6.       <item name="textAllCaps">false</item>  
  7. </style>  

然后在getPageTitle方法中设置上有标题的tab
[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public CharSequence getPageTitle(int position) {  
  3.     // Generate title based on item position  
  4.     Drawable image = context.getResources().getDrawable(imageResId[position]);  
  5.     image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());  
  6.     // Replace blank spaces with image icon  
  7.     SpannableString sb = new SpannableString("   " + tabTitles[position]);  
  8.     ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);  
  9.     sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);  
  10.     return sb;  
  11. }  

TabLayout还支持自定义View,通过getTabView来设置,这里就不讲怎么实现了,有兴趣的可以自行研究。
 

部分代码:https://github.com/xiangzhihong/jingdongApp

posted @ 2017-04-21 22:15  天涯海角路  阅读(400)  评论(0)    收藏  举报