您的位置:首页 > 其它

ViewPager+Indicator(如何写indicator)

2015-11-23 21:02 344 查看

一:概述

这个教程好像网上挺多的。viewpager用fragment作为每一个item,但是似乎好像indicator似乎都有点不太满意,下面的滑动条是直接跳动的,不是类似动画滑动的。现在就说说这个滑动条。然后再说说其他的东西(比如activity传数据给fragment啊。这些)。

先看看效果图:



二:源码解读

我们先讲讲viewpager吧。

[code]private MyPageAdapter adapter ;
private ViewPager pager;
private List<MyFragment> listFragment ;
...
//这里初始化10个fragment
  for(int i = 0 ;i < 10 ;i ++){
            Bundle bundle = new Bundle();
            bundle.putString("who","hello world "+ i);
            MyFragment fragment = MyFragment.getInstance(bundle);
            listFragment.add(fragment);
  }


通过activity传数据给fragment,直接调用fr.setArguments(bundle);就可以了。bundle就是数据集,然后在fragment中直接调用Bundle bundle = getArguments();就可以获得了。

[code]public static MyFragment getInstance(Bundle bundle){
        MyFragment fr = new MyFragment();
        fr.setArguments(bundle);
        return fr;
 }


然后为viewpager添加适配器。注意其中的getPageTitle()方法,这个方法的返回值就可以作为indicator中的值。

[code]class MyPageAdapter extends FragmentPagerAdapter {

        public MyPageAdapter(FragmentManager fm) {
            super(fm);
        }
        @Override
        public Fragment getItem(int position) {
            return listFragment.get(position);
        }

        @Override
        public long getItemId(int position) {
            return super.getItemId(position);
        }

        @Override
        public int getCount() {
            return listFragment.size();
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return "title - "+position;
        }
    }


然后看看TestIndicatorActivity这个activity实现了MyIndicator.CustomeTextViewInter 接口

主要实现了两个方法,用来让开发者可以直接在代码中自定义indicator,被选择或者没有被选择的效果

selected():被选择的效果。

unSelect():没有被选择的效果。

两个都只是简单的修改了下背景颜色而已。(你们可以实现自己想实现的,比如加粗等等。)

[code] @Override
    public TextView selected(TextView tv) {
        tv.setBackgroundColor(Color.parseColor("#8FFF58"));
        return tv;
    }

    @Override
    public TextView unSelect(TextView tv) {
        tv.setBackgroundColor(Color.parseColor("#FFFFFF"));
        return tv;
    }


我们只需要写下两句代码就可以使用indicator。

[code]//自定义被选择,没被选择的接口
indicator.setCustomeTextViewInter(this);
...
indicator.setViewPager(pager);


好了我们详细说说indicator的实现方法。

我写了个attr文件(好像叫自定义属性文件)

[code]<resources>
    <declare-styleable name="MyIndicator">
        <attr name="lineHeight" format="dimension"/>
        <attr name="lineColor" format="color"/>
    </declare-styleable>
</resources>


然后在布局文件中调用如下就可以

记得在Android studio 布局文件的根元素中加入

xmlns:custom=”http://schemas.android.com/apk/res-auto”

[code] <com.example.tongmin.testproject.MyIndicator
        android:layout_width="match_parent"
        android:layout_height="50dp"
        custom:lineColor="#5680FF"
        custom:lineHeight="5dp"
        android:id="@+id/myindicator"
  />


使用下面的代码就可以读取其中的数据了。

[code] TypedArray a = context.getTheme()
 .obtainStyledAttributes(attrs, R.styleable.MyIndicator, defStyleAttr, 0);

 lineHeight = a.getDimension(R.styleable.MyIndicator_lineHeight, 10);
 lineColor = a.getColor(R.styleable.MyIndicator_lineColor, Color.BLACK);
 a.recycle();


然后整个indicator时继承自 HorizontalScrollView ,因为都是横着滑动的。

然后看看下面代码。注释也看看

[code]//首先将自带的横向的滑动条禁用掉。
this.setHorizontalScrollBarEnabled(false);
//因为scrollview只能有一个子元素,就添加个LinearLayout
linearContain = new LinearLayout(context);
linearContain.setOrientation(LinearLayout.HORIZONTAL);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
this.addView(linearContain, params);


然后看看setViewPager()这个方法,将viewpager设置进来后做了一些初始化工作。

setheader就是将有多少个fragment,然后就初始化多少个indicator的item。

[code] public void setViewPager(ViewPager viewPager) {
        this.viewPager = viewPager;
        this.viewPager.addOnPageChangeListener(this);
        setHeader();
        changeTextView(0);
 }


这个就是添加一个个item的具体的方法。其中添加的其实是textview。

因为我们放出了一个接口,让用户自己实现选择,没被选择的textview。所以需要做一下判断。

[code] private void addTextView(String text , int position) {
        //判断用户是否自定义了textview
        TextView textView = new Text(context,position);
        if (customeTextViewInter != null) {
            textView = customeTextViewInter.unSelect(textView);
            if (textView == null) {
                throw new RuntimeException("customeTextViewInter textview == null");
            }
        }
        textView.setText(text);
        linearContain.addView(textView);
 }


其中Text是自定义的TextView,其中的position属性是记录我这个textView是第几个item,因为要添加点击事件,点击跳转到对应fragment。

然后注意还写了params.bottomMargin = (int) lineHeight;

这个是为了下面的滑动条腾出空间来。不然把他遮挡了。

[code]private class Text extends TextView {
    int position;
    public Text(Context context , int position) {
         super(context);
         this.position = position;
         this.init(context);
    }
    private void init(Context context) {

      LinearLayout.LayoutParams params = 
        new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,            ViewGroup.LayoutParams.MATCH_PARENT);

            this.setLayoutParams(params);
            int size = dip2px(context, 10);
            params.bottomMargin = (int) lineHeight;
            this.setPadding(size, 0, size, 0);
            this.setGravity(Gravity.CENTER);
            this.setTextSize(20);
            this.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    viewPager.setCurrentItem(position);
                }
            });
        }
    }


好了。现在我们手动为这个viewpager设置一个ViewPager.OnPageChangeListener

监听viewpager的滑动。

这个接口需要实现三个方法。

1.onPageScrolled()是在滑动的时候回调的一个接口。

[code]      a).position是在滑动的时候所在的position(比如我在第一个fragment滑动到第二个fragment的时候这个position就是0,从0开始的啊。)
      b).positionOffset就是当前的滑动在整个viewpager的比例。
      c).positionOffsetPixels。就是这个fragment滑动的总像素数。


2.onPageSelected()是在滑动到被选择的fragment回调的。

[code]      a).position就是被选择的position。(从第一个滑向第二个,这个position就指向第二个)。


[code]   @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        changeLinePosition(position, positionOffset);
    }
    @Override
    public void onPageSelected(int position) {
        changeTextView(position);
    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }


我们触发滑动条滑动时间就是在onPageScrolled()中,然后修改textview的样式的时在onPageSelected();

我们看看changeLinePosition();方法

首先找到对应的textview然后算出他的宽度。

currentPosition 就是当前滑动条所在的 X 坐标。

this.scrollTo((int) currentPosition - scroll, 0);

是让当前HorizontalScrollView滑动到指定位置。不然会出现像滑动条已经到最右边了。但是scrollview并没有滚动过去。就看不见了。

看下图:



[code]private void changeLinePosition(int position, float offset) {
        int left = linearContain.getChildAt(position).getLeft();
        int right = linearContain.getChildAt(position).getRight();
        lineWidth = right - left;
        offset = lineWidth * offset;
        currentPosition = left + offset;
        this.scrollTo((int) currentPosition - scroll, 0);
        invalidate();
 }


最后在ondraw()方法中,画出下面的滑动条就可以了。找到自己的坐标就可以了。

[code] @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int textHeight = linearContain.getHeight();
        canvas.drawRect(currentPosition, textHeight - lineHeight, 
          currentPosition + lineWidth, textHeight, linePaint);
    }


源码下载

加个好友共同学习(不是公众号):



因为小弟水平有限,如果有写的有问题,希望指出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: