Android指示器。

主要实现的思路:

1、自定义viewIndicator,使它继承LinearLayout
2、画三角形,计算三角形所在的位置
3、viewpage与tab之间产生联动。
分开一步步来说:
一、tab栏中自定义viewIndicator,主要代码为:

public class ViewIndicator extends LinearLayout {
    private  TypedArray array;
    //画笔
    private Paint mPaint;
    //三角形
    private Path mPath;
    //三角形的宽和高
    private int mTrianleWidth;
    private int mTrianleHeight;
    private static final float RADIO_TRIANGLE_WIDTH=1/6F;
    //设置初始化的位置
    private int mInitTranslationX;
    //设置偏移量
    private int mTranslationX;
    private int mTabvisibleCount;
    //默认显示的数量为4
    private static final int COUNT_DEFAULT_TAB = 4;
    private List<String> mTitles;
    //正常状态下的字体颜色
    private static final int COLOR_TEXT_NORMAL=0x77FFFFFF;
    //正常状态下的字体颜色
    private static final int COLOR_TEXT_HIGH=0xFFFFFFFF;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mTrianleWidth= (int) (w/mTabvisibleCount*RADIO_TRIANGLE_WIDTH);
        mInitTranslationX=w/mTabvisibleCount/2-mTrianleWidth/2;
        initTriangle();

    }
//初始化三角形
    private void initTriangle() {
        mTrianleHeight=mTrianleWidth/2;
        mPath=new Path();
        //首先是在原点的位置
        mPath.moveTo(0,0);
        //三角形的底边首先移动,x轴是x的宽度,y轴为0;(0,0)△(三角形宽度mTrianleWidth,0)
        mPath.lineTo(mTrianleWidth,0);
        //再向左上方移动,如果为等腰三角形,Y轴方向的高度与mTrianleWidth/2相等,y轴向下是正数
        mPath.lineTo(mTrianleWidth/2,-mTrianleHeight);
        //闭合,形成三角形。
        mPath.close();
    }

    public ViewIndicator(Context context) {
        this(context,null);

    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.save();

        canvas.translate(mInitTranslationX+mTranslationX,getHeight() +2);
        canvas.drawPath(mPath,mPaint);
        canvas.restore();
        super.dispatchDraw(canvas);
    }

    public ViewIndicator(Context context, AttributeSet attrs) {
        super(context, attrs);
        //获取自定义属性,可见Tab的数量
        array=context.obtainStyledAttributes(attrs,R.styleable.ViewIndicator);
        mTabvisibleCount=array.getInt(R.styleable.ViewIndicator_visible_tab_count,COUNT_DEFAULT_TAB);
        if (mTabvisibleCount<0){
            mTabvisibleCount=COUNT_DEFAULT_TAB;
        }
array.recycle();
        //初始化画笔
        mPaint=new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.FILL);
        //设置圆角效果,不至于太尖锐
        mPaint.setPathEffect(new CornerPathEffect(3));
    }
//当xml加载完后运行该方法
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        //拿到子元素的个数
        int cCount=getChildCount();
        if (cCount==0){
            return;
        }
        for (int i = 0; i <cCount ; i++) {
            View view=getChildAt(i);
            //获取参数,重新动态布局
            LinearLayout.LayoutParams lp= (LayoutParams) view.getLayoutParams();
            //如果设置了权重,此时将权重设置为0
            lp.weight=0;
            //将宽度设置为平分。屏幕宽度除以可见数量
            lp.width=getScreenWidth()/mTabvisibleCount;
            //设置参数
            view.setLayoutParams(lp);

        }
    }
//获取屏幕宽度
    private int getScreenWidth() {
        WindowManager wm= (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics=new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    };

    /**
     * 指示器跟随着viewpager一起移动。
     * @param position
     * @param offset
     */
    public void scoll(int position,float offset) {
        int tabwidth=getWidth()/mTabvisibleCount;
        mTranslationX= (int) (tabwidth*(offset+position));
        //容器移动,当tab处于移动的最后一个时,当可见tab不为1
        if (mTabvisibleCount!=1) {
            if (position >= (mTabvisibleCount - 2) && offset > 0 && getChildCount() > mTabvisibleCount) {
                this.scrollTo((position - (mTabvisibleCount - 2)) * tabwidth + (int) (tabwidth * offset), 0);
            }
        }else {
            this.scrollTo((int)(tabwidth*(position+offset)),0);
        }
        //三角形发生改变,需要重新绘制
        invalidate();
    }
    public void setTabItemTitles(List<String> titles){
        if (titles!=null&&titles.size()>0){
            this.removeAllViews();
            mTitles=titles;
            for (String title : titles) {
                addView(generateTexeView(title));
            }

        }
        setItemOnclick();
    }
//根据title创建Tab
    private View generateTexeView(String title) {
        TextView tv=new TextView(getContext());
        LinearLayout.LayoutParams lp=new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
        lp.width=getScreenWidth()/mTabvisibleCount;
        tv.setText(title);
        tv.setGravity(Gravity.CENTER);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP,16);
        tv.setTextColor(Color.WHITE);
        tv.setLayoutParams(lp);
        return tv;


    }
    private ViewPager viewPager;
    //设置可显示的tab数目。
public void setVisibleTabCount(int count){
    mTabvisibleCount=count;
}
    //简化activity中的代码
    public void setPageOnchangListen(ViewPager vp, int pos){
        viewPager=vp;
        //为viewpage设置监听器
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

                //当页面发生滚动的时候,偏移量为tabwidth*positionOffset(这是0-1的页面)+position*tabwidth(第二个页面到第三个页面)
                scoll(position,positionOffset);
                //为OnpagerChangeListener中的方法设置
                if(listener!=null) {
                    listener.onPageScrolled(position, positionOffset, positionOffsetPixels);
                }
            }

            @Override
            public void onPageSelected(int position) {
                if(listener!=null)
                listener.onPageSelected(position);
                highLightTextView(position);

            }

            @Override
            public void onPageScrollStateChanged(int state) {
                if(listener!=null)
                listener.onPageScrollStateChanged(state);

            }
        });
        viewPager.setCurrentItem(pos);
        highLightTextView(pos);
    }
    private OnPageChangeListener listener;
    //设置viewpager的回调供选择者使用
    public interface OnPageChangeListener{
        void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
        void onPageSelected(int position);
        void onPageScrollStateChanged(int state);
    }
    //设置一个方法供调用者使用
    public void setOnpageChangeListener(OnPageChangeListener mlistener){
        this.listener=mlistener;
    }
   //重置颜色
    public void resetTextViewColor(){
        for(int i=0;i<getChildCount();i++){
            View view =getChildAt(i);
            if (view instanceof TextView){
                ((TextView) view).setTextColor(COLOR_TEXT_NORMAL);
            }
        }
    }

    //设置颜色字体;
    public void highLightTextView(int pos){
        //重置颜色
        resetTextViewColor();
        View view=getChildAt(pos);
        if (view instanceof TextView){
            ((TextView) view).setTextColor(COLOR_TEXT_HIGH);
        }
    }
    //设置监听器
    public void setItemOnclick(){
        for (int i = 0; i <getChildCount() ; i++) {
           final int j =i;
            View view =getChildAt(i);
            view.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    viewPager.setCurrentItem(j);
                }
            });
        }

    }
}

代码中都有注释,这里主要是想讲解下有关于画三角形:
这里写图片描述
图片比较粗糙,各位将就看下~毕竟不是专业美工出身。首先是设置三角形的起点,调用mpath.lineto()函数,移动坐标。需要注意的是Y轴向上是负,向下为正。最后闭合三角形。

//起点
 mPath.moveTo(0,0);
        //三角形的底边首先移动,x轴是x的宽度,y轴为0;(0,0)△(三角形宽度mTrianleWidth,0)
        mPath.lineTo(mTrianleWidth,0);
        //再向左上方移动,如果为等腰三角形,Y轴方向的高度与mTrianleWidth/2相等,y轴向下是正数
        mPath.lineTo(mTrianleWidth/2,-mTrianleHeight);
        //闭合,形成三角形。
        mPath.close();

在MainActivity中的调用:

public class MainActivity extends FragmentActivity {

    ViewPager viewPager;

    ViewIndicator viewIndicator;
    private List<String> mtitles= Arrays.asList("短信1","收藏2","推荐3","短信4","收藏5","推荐6","短信7","收藏8","推荐9");
    private List<VpsimpleFragment> fragments=new ArrayList<VpsimpleFragment>();
    //fragment的adapter
    private FragmentPagerAdapter mAdapter;




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main2);
//        ButterKnife.bind(this);
        initView();
        initDatas();
        //先设置可显示的数量
        viewIndicator.setVisibleTabCount(4);
        viewIndicator.setTabItemTitles(mtitles);
        viewPager.setAdapter(mAdapter);
//在viewIndicator中设置监听,避免在
     viewIndicator.setPageOnchangListen(viewPager,0);

    }

    private void initView() {
        viewPager= (ViewPager) findViewById(R.id.viewpager);
        viewIndicator= (ViewIndicator) findViewById(R.id.id_indicator);
    }

    private void initDatas() {

        for (String mtitle : mtitles) {
            fragments.add(VpsimpleFragment.newInstance(mtitle));

        }

        mAdapter=new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return fragments.get(position);
            }

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

实现代码比较简单。就不一一阐述了。
关于VpsimpleFragment.java的代码如下:

        private String mtitle;
    public static final String BUNDLE_TITLE="title";


    @Override
    public View onCreateView(LayoutInflater inflater,  ViewGroup container, Bundle savedInstanceState) {
        Bundle bundle=getArguments();
        if (bundle!=null){
            mtitle=bundle.getString(BUNDLE_TITLE);
        }
        TextView textView=new TextView(getActivity());
        textView.setText(mtitle);
        textView.setGravity(Gravity.CENTER);
        return textView;
    }

    //获取实例
    public static VpsimpleFragment newInstance(String title){
        Bundle bundle=new Bundle();
        bundle.putString(BUNDLE_TITLE,title);
        VpsimpleFragment fragment=new VpsimpleFragment();
        fragment.setArguments(bundle);
        return fragment;

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现了ViewPager的指示器。标题指示器(TitleIndicator)用于每个ViewPager页标题的切换。图标Tab指示器(IconicTabsView)可以让我们将每个tab做成图标。这俩个指示器你可以选择使用。我做了demo,效果非常不错。而且使用简单。推荐使用。项目地址:https://github.com/MoshDev/AndroidIndicators 效果图:如何使用xml布局中创建ViewPager和指示器<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:orientation="vertical" >     <com.moshx.indicators.title.TitleIndicator         android:textAppearance="?android:attr/textAppearanceMedium"         android:id="@ id/titleIndicator"         android:textColor="@android:color/black"         android:layout_width="300dp"         android:layout_height="wrap_content" />     <com.moshx.indicators.tab.IconicTabsView         android:layout_width="match_parent"         android:id="@ id/iconicTabsView"         android:layout_height="wrap_content" />     <android.support.v4.view.ViewPager         android:id="@ id/viewPager"         android:layout_width="match_parent"         android:layout_height="match_parent" /> </LinearLayout><com.moshx.indicators.title.TitleIndicator>和<com.moshx.indicators.tab.IconicTabsView>你根据你的需要添加。2. java代码中未ViewPager添加指示器ViewPager mViewPager = (ViewPager) findViewById(R.id.viewPager); mViewPager.setAdapter(new MyAdapter(getSupportFragmentManager()));          //创建ViewPager观察者,用于监听ViewPager的切换 final ViewPagerObserver observer = new ViewPagerObserver(mViewPager); //标题指示器 titleIndicator = (TitleIndicator) findViewById(R.id.titleIndicator); observer.addObservableView(titleIndicator);          //tabs指示器 IconicTabsView iconicTabsView = (IconicTabsView) findViewById(R.id.iconicTabsView); iconicTabsView.setIconicTabsEffect(new GreyscaleIconicTabsEffect()); observer.addObservableView(iconicTabsView);ok。完整的实例你可以点击上面的"下载源码"获得。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值