按照惯例先上图,一种是三角形,一种是最常用的下划线
实现思路,主要是在onPageScroll里面进行指示器滑动距离和父容器滑动距离的计算,然后进行滑动,滑动解决了其他就比较简单了。
顶部就是自定义的ViewPagerIndicator,下面就是Fragment+FragmentPagerAdagter
主MainActivity代码,就是常规的ViewPagerIndicator结合Fragment
public class IndicatorActivity extends AppCompatActivity {
private ViewPagerIndicator indicator;
private ViewPager mViewPager;
private List<Fragment> mList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_indicator);
mList.add(TitleFragment.newInstance("标题1"));
mList.add(TitleFragment.newInstance("标题2"));
mList.add(TitleFragment.newInstance("标题3"));
mList.add(TitleFragment.newInstance("标题4"));
mList.add(TitleFragment.newInstance("标题5"));
mList.add(TitleFragment.newInstance("标题6"));
mList.add(TitleFragment.newInstance("标题7"));
mList.add(TitleFragment.newInstance("标题8"));
mList.add(TitleFragment.newInstance("标题9"));
indicator = (ViewPagerIndicator) findViewById(R.id.indicator_activity);
indicator.setSelected_indicator(ViewPagerIndicator.LINE);//使用三角形
indicator.selectText(0);//默认选中第一个
mViewPager = (ViewPager) findViewById(R.id.viewpager_indicator);
mViewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), mList));
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
indicator.move(position, positionOffset); //position当前fragment,offset滑动值0-1
}
@Override
public void onPageSelected(int position) {
indicator.selectText(position);//textview选中效果
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
}
Fragment里面就一个textview很简洁
public class TitleFragment extends Fragment {
private static final String PARAM1 = "param1";
private String mParam1;
private Context mContext;
private callback mCb;
public static TitleFragment newInstance(String text) {
TitleFragment fragment = new TitleFragment();
Bundle bundle = new Bundle();
bundle.putString(PARAM1, text);
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context != null) {
mContext = context;
if (context instanceof callback) {
mCb = (callback) context;
}
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(PARAM1);
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//不写xml文件
TextView textView = new TextView(mContext);
textView.setText(mParam1);
textView.setGravity(Gravity.CENTER);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER;
textView.setLayoutParams(lp);
return textView;
}
@Override
public void onDetach() {
super.onDetach();
mCb = null;
}
public interface callback {
void success(String msg);
}
}
Adapter没什么好说的
public class ViewPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> mList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager fm, List<Fragment> mList) {
super(fm);
this.mList = mList;
}
@Override
public Fragment getItem(int position) {
return mList.get(position);
}
@Override
public int getCount() {
return mList.size();
}
}
主角自定义的ViewPagerIndicator,继承的LinnerLayout,在里面加TextView的方式,加了挺多注释的应该很好理解
public class ViewPagerIndicator extends LinearLayout {
private static final String TAG = "ViewPagerIndicator";
public static final int TRIANGLE = 1;//三角形
public static final int LINE = 2;//下划线
public static int selected_indicator = TRIANGLE;//要使用的指示器
private int mScreenWidth;//屏幕宽
private int mTitleWidth;//每个标题宽
private int mTriangleWidth;//三角宽
private int mInitLeftMargin;//初始化的三角x位置
private int mMoveMargin = 0;//计算出来的移动x位置
private int mTriangleY;//三角形底部的位置Y
private int mTitleCount = 9;//标题总数
private int mVisibableCount = 3;//一屏显示标题数量
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);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mScreenWidth = wm.getDefaultDisplay().getWidth();
//初始化一些指示器的宽高参数
mTitleWidth = mScreenWidth / 3;//默认每个标题占屏幕三分之一宽
mTriangleWidth = mScreenWidth / 3 / 6;//一个三角形底边占每个标题六分之一
mInitLeftMargin = mScreenWidth / 3 / 2 - (mTriangleWidth / 2);//初始化第一次三角在标题下居中
mTriangleY = DensityUtil.dip2px(context, 50);//xml标题栏高50dp
Log.d(TAG, mScreenWidth + "-" + mTriangleWidth + "-" + mInitLeftMargin);
//获取标题数量
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator);
mTitleCount = array.getInt(R.styleable.ViewPagerIndicator_titleCount, mTitleCount);
array.recycle();
//生成标题
for (int i = 0; i < mTitleCount; i++) {
TextView textView = new TextView(context);
textView.setText("标题" + (i + 1));
textView.setTextColor(getResources().getColor(R.color.titile_text_color));
textView.setGravity(Gravity.CENTER);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(mScreenWidth / mVisibableCount, ViewGroup.LayoutParams.MATCH_PARENT);
textView.setLayoutParams(lp);
addView(textView);
}
}
//指示器+容器滚动
public void move(int pos, float offset) {
if (selected_indicator == TRIANGLE) {
mMoveMargin = (int) (mInitLeftMargin + pos * mTitleWidth + (offset * mTitleWidth));//三角形移动
}else if (selected_indicator == LINE) {
mMoveMargin = (int) (pos * mTitleWidth + (offset * mTitleWidth));//线移动
}
//容器滚动,在一屏倒数第二个才允许
if (pos >= mVisibableCount - 2 && pos < mTitleCount - 2) {
scrollTo((int) ((pos - (mVisibableCount - 2)) * mTitleWidth + (mTitleWidth * offset)), 0);
}
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画三角形画笔
Paint paint = new Paint();
paint.setColor(getResources().getColor(R.color.master_color));
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(10.0f);//线宽
if (selected_indicator == TRIANGLE) {
if (mMoveMargin == 0) {//不是第一次draw,使用移动的值
mMoveMargin = mInitLeftMargin;
}
//直角三角形
Path path = new Path();
path.moveTo(mMoveMargin, mTriangleY);//左点
path.lineTo(mMoveMargin + mTriangleWidth, mTriangleY);//右点
path.lineTo(mMoveMargin + (mTriangleWidth / 2), mTriangleY - (mTriangleWidth / 2));//上点
path.close();
canvas.drawPath(path, paint);
}else if (selected_indicator == LINE) {
canvas.drawLine(mMoveMargin, mTriangleY, mTitleWidth + mMoveMargin, mTriangleY, paint);
}
}
public void setSelected_indicator(int selected_indicator) {
this.selected_indicator = selected_indicator;
}
//选中改变字体颜色
public void selectText(int position) {
TextView textView;
for (int i = 0; i < mTitleCount; i++) {
textView = (TextView) getChildAt(i);
if (position == i) {
textView.setTextColor(getResources().getColor(R.color.colorAccent));
} else {
textView.setTextColor(getResources().getColor(R.color.titile_text_color));
}
}
}
}
代码基本贴完了,就不上传工程了,写了大半天时间,有些问题可能没考虑到,见谅一下,毕竟才一百行,不过麻雀虽小五脏俱全啊。