自定义View实现顶部Tab指示器
2016-04-11 20:48
375 查看
自定义View实现顶部Tab指示器,代码非常简单和简洁。另外Fragment切换时也能避免不必要重绘。
源代码:GitHub
![](http://img.my.csdn.net/uploads/201604/11/1460378771_7277.gif)
我们通过继承LinearLayout来实现指示器的效果。
自定义Indicator代码:
注释很清楚了,代码也很简单,不赘述了。
布局:
把自定义的View放在AppBarLayout中而不放在content_main,是因为让ToolBar和指示器高度一致,不明白的话,试一下你就知道啥意思了。
代码:
这个比较简单,就是ViewPager结合Fragment,最关键的是这行代码:
它的作用是把ViewPager的滑动和指示器的滑动结合在一起了。
值得一提的是,Fragment的这种写法可以避免布局过多的重绘。如果你已经知道的话,请闭嘴...........
还是比较简单的。
当然,你并不需要重复造轮子,官方Design库中已经提供TabLayout+ViewPager实现顶部Tab指示器,绘制什么的都在XML属性定义,而且提供了很多形式的Tab类型,功能极其强大。
最后值得说明的是,这个很赞的小功能,我特么怎么能想的起来...............呀。这个是由一位大神在2014年奉献出来的大神,速度去膜拜。
好了,我该洗洗睡了。
狂戳:GitHub
源代码:GitHub
效果图:
![](http://img.my.csdn.net/uploads/201604/11/1460378771_7277.gif)
自定义View:
我们通过继承LinearLayout来实现指示器的效果。
自定义Indicator代码:
/** * Created by gaolonglong on 2016/4/7. */ public class Indicator extends LinearLayout { //Indicator的宽和高 private int mWidth; private int mHeight = 5; //Indicator的左、上坐标 private int mTop; private int mLeft; //自定义属性 private int mColor; //LinearLayout的子View数 private int mChildCount; private int pos; private Paint mPaint; public Indicator(Context context) { this(context, null); } public Indicator(Context context, AttributeSet attrs) { this(context, attrs, 0); } public Indicator(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //setBackgroundColor(Color.TRANSPARENT); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Indicator, 0, 0); mColor = array.getColor(R.styleable.Indicator_indicatorColor, Color.RED); array.recycle(); init(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(mColor); } @Override protected void onFinishInflate() { super.onFinishInflate(); //获取子View数量,也就是TextView数 mChildCount = getChildCount(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mTop = getMeasuredHeight(); //LinearLayout的宽和高 int width = getMeasuredWidth(); int height = mTop + mHeight; mWidth = width / mChildCount; //设置测量款和高 setMeasuredDimension(width,height); } /** * 只要ViewPager一直在滑动就会调用onPageScrolled方法进而调用scroll方法 * 参数position是当前ViewPager位置 * 参数offset是当前ViewPager的偏移量,大小是0~1的, * 而我们指示器的偏移正好是使用这个参数实现的 */ public void scroll(int position,float offset){ mLeft = (int) ((position + offset) * mWidth); pos = position; //ViewPager不断偏移就不断重绘指示器位置 invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //绘制指示器 Rect rect = new Rect(mLeft,mTop,mLeft + mWidth,mTop + mHeight); canvas.drawRect(rect, mPaint); //每次重绘都重置文字颜色 resetColor(); //并设置被选中的和当前ViewPager对应的文字颜色 TextView tv = (TextView) getChildAt(pos); tv.setTextColor(Color.WHITE); } private void resetColor() { for (int i = 0;i < mChildCount;i++){ TextView tv = (TextView) getChildAt(i); tv.setTextColor(Color.parseColor("#D0D8DC")); } } }
注释很清楚了,代码也很简单,不赘述了。
使用Indicator:
布局:<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="com.gaolonglong.app.tabindicator.MainActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" /> <com.gaolonglong.app.tabindicator.Indicator android:id="@+id/indicator" app:indicatorColor="#FF0000" android:paddingTop="13dp" android:paddingBottom="13dp" android:weightSum="3" android:background="?attr/colorPrimary" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/home_tab" android:text="首页" android:textSize="18sp" android:gravity="center" android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" /> <TextView android:id="@+id/radio_tab" android:text="电台" android:textSize="18sp" android:gravity="center" android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" /> <TextView android:id="@+id/ranking_tab" android:text="排行榜" android:textSize="18sp" android:gravity="center" android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" /> </com.gaolonglong.app.tabindicator.Indicator> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" /> </android.support.design.widget.CoordinatorLayout>
把自定义的View放在AppBarLayout中而不放在content_main,是因为让ToolBar和指示器高度一致,不明白的话,试一下你就知道啥意思了。
代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Indicator indicator; private ViewPager viewPager; private FragmentPagerAdapter mAdapter; private List<Fragment> list; private TextView homeTab,radioTab,rankingTab; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); initView(); initEvent(); } private void initEvent() { //Listener viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { Log.e("666",position+"...."+positionOffset); indicator.scroll(position,positionOffset); } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { } }); //Click homeTab.setOnClickListener(this); radioTab.setOnClickListener(this); rankingTab.setOnClickListener(this); } private void initView() { //View indicator = (Indicator) findViewById(R.id.indicator); viewPager = (ViewPager) findViewById(R.id.view_pager); homeTab = (TextView) findViewById(R.id.home_tab); radioTab = (TextView) findViewById(R.id.radio_tab); rankingTab = (TextView) findViewById(R.id.ranking_tab); //List list = new ArrayList<Fragment>(); list.add(new HomeFragment()); list.add(new RadioFragment()); list.add(new RankingFragment()); //Adapter mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) { @Override public Fragment getItem(int position) { return list.get(position); } @Override public int getCount() { return list.size(); } }; viewPager.setAdapter(mAdapter); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.home_tab: homeTab.setTextColor(Color.WHITE); viewPager.setCurrentItem(0); break; case R.id.radio_tab: homeTab.setTextColor(Color.WHITE); viewPager.setCurrentItem(1); break; case R.id.ranking_tab: homeTab.setTextColor(Color.WHITE); viewPager.setCurrentItem(2); break; } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
这个比较简单,就是ViewPager结合Fragment,最关键的是这行代码:
indicator.scroll(position,positionOffset);
它的作用是把ViewPager的滑动和指示器的滑动结合在一起了。
值得一提的是,Fragment的这种写法可以避免布局过多的重绘。如果你已经知道的话,请闭嘴...........
public class HomeFragment extends Fragment { private View rootView; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (rootView == null){ Log.e("666","HomeFragment"); rootView = inflater.inflate(R.layout.home_fragment, container, false); } ViewGroup parent = (ViewGroup) rootView.getParent(); if (parent != null){ parent.removeView(rootView); } return rootView; } }
还是比较简单的。
当然,你并不需要重复造轮子,官方Design库中已经提供TabLayout+ViewPager实现顶部Tab指示器,绘制什么的都在XML属性定义,而且提供了很多形式的Tab类型,功能极其强大。
最后值得说明的是,这个很赞的小功能,我特么怎么能想的起来...............呀。这个是由一位大神在2014年奉献出来的大神,速度去膜拜。
好了,我该洗洗睡了。
狂戳:GitHub
相关文章推荐
- Android中自定义控件之液位指示器
- Android TabLayout(选项卡布局)简单用法实例分析
- TabLayout 与 FragmentTabHost
- 使用tablayout 打造高度不一样的tab
- TabLayout的使用分享
- Support Design Library 之 TabLayout 使用与分析
- TabLayout的使用
- iOS 一个带动画的等待指示器
- MaterialDesign 之TabLayout和ViewPager
- ios自定义hub指示器
- Android 自定义的颜色滑动转换ViewPager指示器 ColorTransformIndicator
- android.support.design.widget.TabLayout 用法解析
- TabLayout android Tab的一种实现方式
- AndroidDesignSupportLibrary 之 TabLayout
- TabLayout 简单实现底部图标文字导航,实现滑动底部变化效果
- 关于在eclipse中导入android support design包出错的问题【不定时更新】
- Android 教你打造炫酷的ViewPagerIndicator
- 自定义view:图片显示指示器
- Android TabLayout使用注意点。
- 使用Android Support Design 控件TabLayout 方便快捷实现选项卡功能