ScrollView+指示器

来源:互联网 发布:淘宝什么是权重 编辑:程序博客网 时间:2024/06/14 03:55


最近干了一段时间的活,产品要求完成混动指示器的功能,也就是说上面有tab标题,当滑动到不同的位置之后,标题切换,且点击标题也可以使得scrollview,滑动到对应的位置,我看了看网上的例子觉得挺少程度,这里就分享一些经验给大家,第一自定义一个类似标题栏的指示器

public class CustomerIndicatior extends LinearLayout {    /**     * 绘制矩形的画笔     */    private Paint mPaint;    /**     * path构成一个矩形     */    private Path mPath;    /**     * 矩形的宽度     */    private int mRectangleWidth;    /**     * 初始时,矩形指示器的偏移量     */    private int mInitTranslationX;    /**     * 手指滑动时的偏移量     */    private float mTranslationX;    /**     * 默认的Tab数量     */    private static final int COUNT_DEFAULT_TAB = 4;    /**     * tab数量     */    private int mTabVisibleCount = COUNT_DEFAULT_TAB;    /**     * 与之绑定的ViewPager     */    public ViewPager mViewPager;    /**     *  对外的ViewPager的回调接口     */    private ViewPagerIndicator.PageChangeListener onPageChangeListener;    /**     * 文本默认颜色     */    private int textColor;    /**     * 指示器颜色和文字高亮时的颜色     */    private int underlineColor;    /**     * 控件最底下的那一条线     */    private boolean DrawBottomLine ;    /**     * 指示器的高度     */    private float underlineHeight;    /**     * 画最底下的线的画笔     */    private Paint mDrawLinePaint;    private ScroViewChangeListener scroViewChangeListener;    public CustomerIndicatior(Context context) {        this(context, null);    }    public CustomerIndicatior(Context context, AttributeSet attrs) {        super(context, attrs);        // 获得自定义属性        TypedArray a = context.obtainStyledAttributes(attrs, com.enjoylink.view.lib.R.styleable.ViewPagerIndicator);        mTabVisibleCount = a.getInt(com.enjoylink.view.lib.R.styleable.ViewPagerIndicator_visibilitycount,COUNT_DEFAULT_TAB);        textColor = a.getColor(com.enjoylink.view.lib.R.styleable.ViewPagerIndicator_textcolor, Color.parseColor("#ffffff"));        underlineColor = a.getColor(com.enjoylink.view.lib.R.styleable.ViewPagerIndicator_underlinecolor, Color.parseColor("#1995F7"));        underlineHeight = a.getDimension(com.enjoylink.view.lib.R.styleable.ViewPagerIndicator_underlineheigth, 16);        DrawBottomLine = a.getBoolean(com.enjoylink.view.lib.R.styleable.ViewPagerIndicator_draw_bottom_line, false) ;        if (mTabVisibleCount < 0)            mTabVisibleCount = COUNT_DEFAULT_TAB;        a.recycle();        // 初始化画笔        mPaint = new Paint();        mPaint.setAntiAlias(true);        mPaint.setColor(underlineColor);        mPaint.setStyle(Paint.Style.FILL);        //画group的画笔        mDrawLinePaint = new Paint();        mDrawLinePaint.setAntiAlias(true);        mDrawLinePaint.setColor(Color.parseColor("#dad9dc"));        mDrawLinePaint.setStyle(Paint.Style.FILL);    }    /**     * 画Group     */    @Override    protected void onDraw(Canvas canvas) {        if(DrawBottomLine){            canvas.save() ;            canvas.drawRect(0, getHeight()-underlineHeight/2, getWidth(), getHeight(), mDrawLinePaint);            canvas.restore();        }        super.onDraw(canvas);    }    /**     * 绘制指示器     */    @Override    protected void dispatchDraw(Canvas canvas) {        canvas.save();        // 画笔平移到正确的位置        canvas.translate(mInitTranslationX + mTranslationX, getHeight() + 1);        canvas.drawPath(mPath, mPaint);        canvas.restore();        super.dispatchDraw(canvas);    }    /**     * 初始化矩形的宽度     */    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        // 初始化矩形        initRectangle();        // 初始时的偏移量        mInitTranslationX = getWidth() / mTabVisibleCount / 2 - mRectangleWidth/ 2;    }    /**     * 设置可见的tab的数量     *     * @param count     */    public void setVisibleTabCount(int count) {        this.mTabVisibleCount = count;    }    /**     * 设置tab的标题内容 可选,可以自己在布局文件中写死     *     * @param datas     */    public void setTabItemTitles(List<String> datas) {        // 如果传入的list有值,则移除布局文件中设置的view        if (datas != null && datas.size() > 0) {            this.removeAllViews();            for (String title : datas) {                // 添加view                addView(generateTextView(title));            }            // 设置item的click事件            setItemClickEvent();        }    }    public void setTabItemTitles(String[] datas) {        if (datas != null && datas.length > 0) {            this.removeAllViews();            for (int i=0;i<datas.length;i++) {                addView(generateTextView(datas[i]));            }            setItemClickEvent();        }    }    public void setSeletView(int pos ,float positionOffset) {        scroll(pos, positionOffset);        resetTextViewColor();        highLightTextView(pos);    }    /**     * 高亮文本     *     * @param position     */    protected void highLightTextView(int position) {        View view = getChildAt(position);        if (view instanceof TextView) {            ((TextView) view).setTextColor(underlineColor);        }    }    /**     * 重置文本颜色     */    private void resetTextViewColor() {        for (int i = 0; i < getChildCount(); i++) {            View view = getChildAt(i);            if (view instanceof TextView) {                ((TextView) view).setTextColor(textColor);            }        }    }    /**     * 设置点击事件     */    public void setItemClickEvent() {        int cCount = getChildCount();        for (int i = 0; i < cCount; i++) {            final int j = i;            View view = getChildAt(i);            view.setOnClickListener(new OnClickListener() {                @Override                public void onClick(View v) {                    scroViewChangeListener.onSlectScrolled(j);                }            });        }    }    /**     * 根据标题生成我们的TextView     *     * @param text     * @return     */    private TextView generateTextView(String text) {        TextView tv = new TextView(getContext());        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);        lp.width = getScreenWidth() / mTabVisibleCount;        tv.setGravity(Gravity.CENTER);        tv.setTextColor(textColor);        tv.setText(text);        tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);        if(mRectangleWidth == 0){            TextPaint paint = tv.getPaint() ;            mRectangleWidth = (int) paint.measureText(text) ;        }        tv.setLayoutParams(lp);        return tv;    }    /**     * 初始化矩形指示器     */    private void initRectangle() {        mPath = new Path();        mPath.moveTo(0, 0);        mPath.lineTo(mRectangleWidth, 0);        mPath.lineTo(mRectangleWidth, -underlineHeight);        mPath.lineTo(0, -underlineHeight);        mPath.close();    }    /**     * 设置布局中view的一些必要属性;如果设置了setTabTitles,布局中view则无效     */    @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();            lp.weight = 0;            lp.width = getScreenWidth() / mTabVisibleCount;            view.setLayoutParams(lp);        }        // 设置点击事件        setItemClickEvent();    }    /**     * 获得屏幕的宽度     *     * @return     */    public int getScreenWidth() {        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);        DisplayMetrics outMetrics = new DisplayMetrics();        wm.getDefaultDisplay().getMetrics(outMetrics);        return outMetrics.widthPixels;    }    /**     * 指示器跟随手指滚动,以及容器滚动     *     * @param position     * @param offset     */    public void scroll(int position, float offset) {        /**         *  0-1:position=0 ;1-0:postion=0;         */        // 不断改变偏移量,invalidate        mTranslationX = getWidth() / mTabVisibleCount * (position + offset);        int tabWidth = getScreenWidth() / mTabVisibleCount;        // 容器滚动,当移动到倒数最后一个的时候,开始滚动        if (offset > 0 && position >= (mTabVisibleCount - 2)&& getChildCount() > mTabVisibleCount) {            if (mTabVisibleCount != 1) {                this.scrollTo((position - (mTabVisibleCount - 2)) * tabWidth+ (int) (tabWidth * offset), 0);            } else            // 为count为1时 的特殊处理            {                this.scrollTo(position * tabWidth + (int) (tabWidth * offset),0);            }        }        invalidate();    }    public interface ScroViewChangeListener {        public void onSlectScrolled(int position);    }    public void setOnScroViewChangeListener(ScroViewChangeListener scroViewChangeListener) {        this.scroViewChangeListener = scroViewChangeListener;    }}

第二步需要一个自定义的ScrollView,这里主要是监听ScrollView的滑动距离

public class MyScrollView extends ScrollView {    private static final long DELAY = 100;    private int currentScroll;    private Runnable scrollCheckTask;    /**     * @param context     */    public MyScrollView(Context context) {        super(context);        init();    }    /**     * @param context     * @param attrs     */    public MyScrollView(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    /**     * @param context     * @param attrs     * @param defStyle     */    public MyScrollView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init();    }    private void init() {        scrollCheckTask = new Runnable() {            @Override            public void run() {                int newScroll = getScrollY();                if (currentScroll == newScroll) {                    if (onScrollListener != null) {                        onScrollListener.onScrollStopped();                    }                } else {                    if (onScrollListener != null) {                        onScrollListener.onScrolling();                    }                    currentScroll = getScrollY();                    postDelayed(scrollCheckTask, DELAY);                }            }        };        setOnTouchListener(new OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                if (event.getAction() == MotionEvent.ACTION_UP) {                    currentScroll = getScrollY();                    postDelayed(scrollCheckTask, DELAY);                }                return false;            }        });    }    public interface OnScrollListener {        public void onScrollChanged(int x, int y, int oldX, int oldY);        public void onScrollStopped();        public void onScrolling();    }    private OnScrollListener onScrollListener;    /**     * @param onScrollListener     */    public void setOnScrollListener(OnScrollListener onScrollListener) {        this.onScrollListener = onScrollListener;    }    @Override    protected void onScrollChanged(int x, int y, int oldX, int oldY) {        super.onScrollChanged(x, y, oldX, oldY);        if (onScrollListener != null) {            onScrollListener.onScrollChanged(x, y, oldX, oldY);        }    }    /**     * @param child     * @return     */    public boolean isChildVisible(View child) {        if (child == null) {            return false;        }        Rect scrollBounds = new Rect();        getHitRect(scrollBounds);        return child.getLocalVisibleRect(scrollBounds);    }    /**     * @return     */    public boolean isAtTop() {        return getScrollY() <= 0;    }    /**     * @return     */    public boolean isAtBottom() {        return getChildAt(getChildCount() - 1).getBottom() + getPaddingBottom() == getHeight() + getScrollY();    }}

第三步在Activity中的使用,以下是调用指示器的接口回调处理,指示器ci_indicatior的点击事件,滑动至相应的地点,

和sv_message_show, ScrollView的监听滑动所做的事情, 这里需要主要的是定位地点的高度准确才能做出判断,

看以下示意图

ci_indicatior.setOnScroViewChangeListener(new CustomerIndicatior.ScroViewChangeListener() { //监听指示器的点击    @Override    public void onSlectScrolled(int position) {        if(position==0){            sv_message_show.scrollTo(0,0);        }else if (position==1){            sv_message_show.scrollTo(0,tv_text_line_tow.getTop());        }else if (position==2){            sv_message_show.scrollTo(0,tv_text_line_there.getTop());        }    }});sv_message_show.setOnScrollListener(new MyScrollView.OnScrollListener() {//监听scroView的滚动    @Override    public void onScrollChanged(int x, int t, int oldX, int oldY) {        if (t < tv_text_line_tow.getTop()) {            ci_indicatior.setSeletView(0, 0);        } else if (t < tv_text_line_there.getTop() && t >= tv_text_line_tow.getTop()) {            ci_indicatior.setSeletView(1, 0);        } else if (t >= tv_text_line_there.getTop()) {            ci_indicatior.setSeletView(2, 0);        }    }    @Override    public void onScrollStopped() {        if (sv_message_show.isAtTop()) {            ci_indicatior.setSeletView(0, 0);        } else if (sv_message_show.isAtBottom()) {            ci_indicatior.setSeletView(2, 0);        }    }    @Override    public void onScrolling() {        android.util.Log.d("@", "scrolling...");    }});

最后希望对大家有帮助,第一次分享自己的一些心得,写的不好的地方望见谅

原创粉丝点击