效果
涉及控件
LinearLayout + TextView + ViewPager
参考:
ViewPager 详解(四)—-自主实现滑动指示条
http://blog.csdn.net/harvic880925/article/details/38557517
android 打造炫酷导航栏(仿UC头条)
http://blog.csdn.net/qq_16064871/article/details/50682388
实现
自定义控件
自定义控件 ViewPagerIndicator.java 继承自 LinearLayout ,在里面通过 setTitles()
添加子条目 TextView,并且通过相同的 layout_weight = 1 平分父控件宽度: tv.setLayoutParams(new LayoutParams(0, (int) (mMetrics.density * 36), 1));
需要注意的是通过比重设置宽度时, layout_width 一定要设置为 0dp ,否则文字多少会影响长度。
(1)绘画指示条
mPaint 用来画底下那条灰色线, mPaintSlide 用来画蓝色滑动指示条,在构造函数里初始化。在 dispatchDraw()
里被 canvas 使用,画两个矩形。
dispatchDraw()
在需要刷新的时候就会被调用绘画该控件(还有 onDraw() 等也会被调用)。
canvas.drawRect(0, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight(), mPaint);
canvas.drawRect(mSlideRectLeft, getMeasuredHeight() - 6 * mMetrics.density, mSlideRectRight, getMeasuredHeight(), mPaintSlide);
6 * mMetrics.density
的长度就是 6dp 的像素长度。通过 mMetrics = getResources().getDisplayMetrics();
可以获得当前设备的密度。因为 canvas 绘画的时候单位是像素,所以要进行转换。
(2)设置指示条宽度
指示条的宽度时由条目长度动态决定的,所以在 getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
设置指示条的宽度,它会在本控件第一次 OnPreDraw()
运行时回调,之后会被 removeOnPreDrawListener()
。
指示条宽度计算: mWidth = getMeasuredWidth()/count
,当然指示条的宽度应该与一个条目的长度相同,所以平分 LinearLayout 的长度。
(3)滑动检测
每个条目的长度记录在 mWidth ,左右长度 mSlideRectLeft 和 mSlideRectRight 计算在 ViewPager.OnPageChangeListener
的 onPageScrolled()
里。ViewPager 被滑动时, onPageScrolled()
会被不停回调,因此需要不断计算出新的值。
mSlideRectLeft = position * mWidth + (int) (positionOffset * mWidth);
mSlideRectRight = mSlideRectLeft + mWidth;
代码
自定义控件 ViewPagerIndicator.java
package com.example.testslidingtabapplication;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class ViewPagerIndicator extends LinearLayout {
private static final String TAG = "ViewPagerIndicator";
private final Context mContext;
private final Paint mPaint;
private final Paint mPaintSlide;
private final DisplayMetrics mMetrics;
private final OnClickListener mOnClickListener;
private float mSlideRectLeft;
private float mSlideRectRight;
private List<TextView> mTvList;
private ViewPager mViewPager;
private int mWidth;
public ViewPagerIndicator(Context context) {
this(context, null);
}
public ViewPagerIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
mPaint = new Paint();
mPaint.setColor(ContextCompat.getColor(mContext, android.R.color.darker_gray));
mPaint.setStyle(Paint.Style.FILL);
mPaintSlide = new Paint();
mPaintSlide.setColor(ContextCompat.getColor(mContext, R.color.colorPrimary));
mPaintSlide.setStyle(Paint.Style.FILL);
setBackgroundColor(ContextCompat.getColor(mContext, android.R.color.white));
setPadding(0, 0, 0, 0);
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
int count = mViewPager.getAdapter().getCount();
mWidth = getMeasuredWidth()/count;
mSlideRectLeft = 0;
mSlideRectRight = mSlideRectLeft + mWidth;
mTvList.get(0).setSelected(true);
getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
});
mMetrics = getResources().getDisplayMetrics();
mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = (int) v.getTag();
mViewPager.setCurrentItem(position);
}
};
}
@Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
canvas.drawRect(0, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight(), mPaint);
canvas.drawRect(mSlideRectLeft, getMeasuredHeight() - 6 * mMetrics.density, mSlideRectRight, getMeasuredHeight(), mPaintSlide);
//Log.d(TAG, "mSlideRectLeft=" + mSlideRectLeft + " mSlideRectRight=" + mSlideRectRight);
canvas.restore();
super.dispatchDraw(canvas);
}
public void setTitles(List<String> titles) {
List<TextView> tvList = new ArrayList<>();
mTvList = tvList;
int position = 0;
for (String title : titles) {
TextView tv = generateTitleView(title, position++);
tvList.add(tv);
addView(tv);
}
}
private TextView generateTitleView(String title, int position) {
TextView tv = new TextView(mContext);
tv.setLayoutParams(new LayoutParams(0, (int) (mMetrics.density * 36), 1));
tv.setGravity(Gravity.CENTER);
tv.setTextColor(ContextCompat.getColorStateList(mContext, R.color.selector_tab_color));
tv.setTextSize(16);
tv.setText(title);
tv.setTag(position);
tv.setOnClickListener(mOnClickListener);
return tv;
}
public void setViewPager(ViewPager viewPager) {
mViewPager = viewPager;
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
mSlideRectLeft = position * mWidth + (int) (positionOffset * mWidth);
mSlideRectRight = mSlideRectLeft + mWidth;
//Log.d(TAG, "addOnPageChangeListener mSlideRectLeft=" + mSlideRectLeft + " mSlideRectRight=" + mSlideRectRight);
invalidate();
}
@Override
public void onPageSelected(int position) {
for (TextView view : mTvList) {
if (view == mTvList.get(position)) {
view.setSelected(true);
} else {
view.setSelected(false);
}
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
}
selector
TextView 的颜色配置 selector_tab_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="@color/colorPrimary"/>
<item android:state_pressed="true" android:color="@color/colorPrimary"/>
<item android:color="@android:color/black"/>
</selector>
Activity
Main2Activity.java
package com.example.testslidingtabapplication;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class Main2Activity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
final List<View> list = new ArrayList<>();
TextView textView1 = new TextView(this);
textView1.setText("1");
list.add(textView1);
TextView textView2 = new TextView(this);
textView2.setText("2");
list.add(textView2);
TextView textView3 = new TextView(this);
textView3.setText("3");
list.add(textView3);
TextView textView4 = new TextView(this);
textView3.setText("4");
list.add(textView4);
viewPager.setAdapter(new PagerAdapter() {
@Override
public int getCount() {
return list.size();
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(list.get(position));
return list.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(list.get(position));
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
});
ViewPagerIndicator viewPagerIndicator
= (ViewPagerIndicator) findViewById(R.id.viewPagerIndicator);
List<String> titleList = new ArrayList<>();
titleList.add("消息");
titleList.add("联系人");
titleList.add("我");
titleList.add("关于");
viewPagerIndicator.setTitles(titleList);
viewPagerIndicator.setViewPager(viewPager);
}
}
布局
这是 Android Studio 创建 Activity 时自动生成的布局文件 content_main2.xml 。
在里面添加 自定义的导航栏 com.example.testslidingtabapplication.ViewPagerIndicator ,和 ViewPager 。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/content_main2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="0dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="0dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.example.testslidingtabapplication.Main2Activity"
tools:showIn="@layout/activity_main2">
<com.example.testslidingtabapplication.ViewPagerIndicator
android:id="@+id/viewPagerIndicator"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/viewPagerIndicator"/>
</RelativeLayout>