ListView个性化滑动指示器酷炫效果

前几天看到有好多人搞了一个listView的一个指示特效。然后自己参考了一下

Markdown

面对这样的效果年会想起来几种思路?
- 自定义scrollView+scrollBar
- 自定义ListView+自定义ScrollBar
- 自定义 RecycleView
- 自定义Behavior
- 自定义listView + PopuWindows
- 自定义ViewGroup
这几种哪一种是最合适的呢?

分析
  • 首先不看滑动弹出效果,一般来说自定义ListView+自定义ScrollBar是最合适的
  • 自定义 RecycleView 多此一举
  • 自定义Behavior把问题简单复杂话了
  • 自定义scrollView+scrollBar需要重新构造ListView ,重写onDraw,小题大作
  • 自定义ViewGroup 过程太繁琐
  • 如果使用自定义listView + PopuWindows对scrollBar进行设置弹出效果,由于popupWindow是窗体,更不合适是现实出现一个气泡和LISView的scrollBar试试监听的结合。
  • 首先我们确定的是:
    • 自定义ListView
    • 对ScrollBar进行监听和操作
话不多少,还是上代码吧:

MyScrollbarListview.java:

/**
 * 类功能描述:</br>
 *
 * @author yuyahao
 * @version 1.0 </p> 修改时间:</br> 修改备注:</br>
 */

public class MyScrollbarListview  extends ListView implements AbsListView.OnScrollListener {
    private View mScrollPanelView;
    private int mMeasureWidthSpect ;
    private int mMeasureHeghtSpect ;
    /**
     * 定义y轴的滑动变量,在onScroll里不断去判断和负值
     */
    private int mScrollbarPanelPosition = 0;
    private Animation mComeInAnimation = null;
    private Animation mGoOutAnimation = null;

    /**
     *
     * 定义指示器在Y轴的高度
     */
    private int mThumbOffset = 0;
     private int mLastPosition = - 1;
    private OnPositionListener onPositionListener;
    public MyScrollbarListview(Context context, AttributeSet attrs) {
        super(context, attrs);
        super.setOnScrollListener(this);
        TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.MyScrollbarListview);
        int LayoutId = -1,inAnimation = -1,outAnimation = -1;
        if(typeArray != null){
            LayoutId = typeArray.getResourceId(R.styleable.MyScrollbarListview_scrollBarPanel,-1);
            inAnimation = typeArray.getResourceId(R.styleable.MyScrollbarListview_scrollBarComeInAnamation,-1);
            outAnimation  = typeArray.getResourceId(R.styleable.MyScrollbarListview_scrollBarGoOutAnamation,-1);
            typeArray.recycle();
        }
        if(inAnimation != -1){
            mComeInAnimation = AnimationUtils.loadAnimation(context,inAnimation);
        }else{
            mComeInAnimation =  AnimationUtils.loadAnimation(context,R.anim.transation_animation_left);
        }
        if(outAnimation != -1){
            mGoOutAnimation = AnimationUtils.loadAnimation(context,outAnimation);
        }else{
            mGoOutAnimation = AnimationUtils.loadAnimation(context,R.anim.transation_animation_right);
        }
        setMyPanelViewId(LayoutId);
        int drutionMmillis = ViewConfiguration.getScrollBarFadeDuration();//得到系统默认的淡出的时间
        mGoOutAnimation.setDuration(drutionMmillis);
        mGoOutAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                if(mScrollPanelView != null){
                    mScrollPanelView.setVisibility(GONE);
                }
            }
            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        });
    }

    private void  setMyPanelViewId(int layoutId){
            mScrollPanelView = LayoutInflater.from(getContext()).inflate(layoutId,this,false);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);//先测量父容器,在对子布局进行测量
        if(mScrollPanelView != null && getAdapter() !=  null){
            measureChild(mScrollPanelView,widthMeasureSpec,heightMeasureSpec);
            this.mMeasureWidthSpect = widthMeasureSpec;
            this.mMeasureHeghtSpect = heightMeasureSpec;
            requestLayout();
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if(mScrollPanelView != null){
            int left = getMeasuredWidth() - mScrollPanelView.getMeasuredWidth() - mScrollPanelView.
                    getVerticalScrollbarWidth();
            mScrollPanelView.layout(left,
                    mScrollbarPanelPosition,
                    left + mScrollPanelView.getMeasuredWidth(),
                    mScrollbarPanelPosition +mScrollPanelView.getMeasuredHeight()
                    );
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        //在ViewGroup绘制的事后
        if(mScrollPanelView != null && mScrollPanelView.getVisibility() == VISIBLE){
            drawChild(canvas,mScrollPanelView,getDrawingTime());
        }
    }

    @Override
    public void onScrollStateChanged(AbsListView absListView, int i) {

    }

    @Override
    public void onScroll(AbsListView absListView, int firstItem, int visisbleTotle, int allTotle) {
            //监听系统滑块在那个位置,设置总结的位置
            //监听回调---》去设置位置---》position
        if(mScrollPanelView != null && onPositionListener != null){
            /**
             * computeHorizontalScrollExtent //滑动条在纵向范围内 自身的高度的幅度--》放大后的
             * computeHorizontalScrollOffset //滑动条在纵向 的位置--》放大后的
             * computeHorizontalScrollRange //比如0-5000,滑动范围--》放大后的
             */
        //利用 平行线分线段成比例定理进行 取值
        //1.划片的高度 / listView的高度 = computeHorizontalScrollExtent / computeHorizontalScrollRange
            int height = Math.round(1.0f * computeVerticalScrollExtent()* getMeasuredHeight()/
                    computeVerticalScrollRange() );
            mThumbOffset = (int) (1.0f * computeVerticalScrollOffset() * height/
                    computeVerticalScrollExtent() );
            int left2 = getMeasuredWidth() - mScrollPanelView.getMeasuredWidth() -
                    mScrollPanelView.getVerticalScrollbarWidth();
         //2得到 滑块Y正中央的位置Y
            mThumbOffset = mThumbOffset + height/ 2;
            mScrollbarPanelPosition = mThumbOffset - height/ 2;
            mScrollPanelView.layout(
                    left2,
                    mScrollbarPanelPosition,
                    left2 + mScrollPanelView.getMeasuredWidth(),
                    mScrollbarPanelPosition +mScrollPanelView.getMeasuredHeight()

            );
            for (int j = 0; j < getChildCount(); j++) {
                View view = getChildAt(j);
                if(view != null){
                 if(mThumbOffset + height/2 > view.getTop() && mThumbOffset + height/2 < view.getBottom()){
                        if(mLastPosition != firstItem + j){
                            mLastPosition = firstItem + j;
                            if(onPositionListener != null){
                                onPositionListener.myPositionChanged(mLastPosition,null,this,mScrollPanelView);
                                //避免宽度发生改变,重新测量其大小
                                measureChild(mScrollPanelView,mMeasureWidthSpect,mMeasureHeghtSpect);
                            }
                    }
                 }
                }
            }
        }

    }

    @Override
    protected boolean awakenScrollBars(int startDelay, boolean invalidate) {
        boolean isWake = super.awakenScrollBars(startDelay, invalidate);
        if(isWake && mScrollPanelView != null){
            if(mScrollPanelView.getVisibility() == GONE){
                mScrollPanelView.setVisibility(VISIBLE);
                if(mComeInAnimation != null){
                    mScrollPanelView.startAnimation(mComeInAnimation);
                }
            }
            mHandler.removeCallbacksAndMessages(null);
            mHandler.removeCallbacks(runTask);
            //设置小时
            mHandler.postAtTime(runTask,startDelay+AnimationUtils.currentAnimationTimeMillis());
        }else{
            mScrollPanelView.setVisibility(GONE);
            if(mComeInAnimation != null){
                mScrollPanelView.startAnimation(mGoOutAnimation);
            }
        }
        return isWake;
    }
    private  Handler mHandler = new Handler();
    private   Runnable runTask = new Runnable() {
        @Override
        public void run() {
            if(mGoOutAnimation != null){
                mScrollPanelView.startAnimation(mGoOutAnimation);
            }
        }
    };
    public  interface OnPositionListener{
         void myPositionChanged(int position,Student student,MyScrollbarListview myScrollbarListView,
                                View mScrollPanelView);
    }
    public void setOnPositionListener(OnPositionListener onPositionListener){
        this.onPositionListener = onPositionListener;
    }
}

入口类MainActivity.java


/**
 * 类功能描述:</br>
 *
 * @author yuyahao
 * @version 1.0 </p> 修改时间:</br> 修改备注:</br>
 */
public class MainActivity extends AppCompatActivity {
    @Bind(R.id.lv_customser_zoomscroll)
    MyScrollbarListview lv_customser_zoomscroll;
    private List<Student> list = new ArrayList<>();
    private ScrollListViewAdapter2 scrollListViewAdapter2;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initData();
    }

    protected void initData() {
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        list.addAll(ServiceData.getStudentList());
        lv_customser_zoomscroll.setOnPositionListener(new MyScrollbarListview.OnPositionListener() {
            @Override
            public void myPositionChanged(int position, Student student, MyScrollbarListview
                    myScrollbarListView, View mScrollPanelView) {
                Student student1 = list.get(position);
                TextView tv = (TextView) mScrollPanelView.findViewById(R.id.iv_name);
                TextView tv_lessons = (TextView) mScrollPanelView.findViewById(R.id.tv_lessons);
                tv.setText("" + student1.getName()+"   "+" level: "+position);
                tv_lessons.setText("科目: "+student1.getList().get(0).getPerListenceName());

            }
        });
        scrollListViewAdapter2 = new ScrollListViewAdapter2(MainActivity.this,list);

        lv_customser_zoomscroll.setAdapter(scrollListViewAdapter2);

    }

}

布局.xml:

<?xml version="1.0" encoding="utf-8" ?>
 <LinearLayout   xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    xmlns:app ="http://schemas.android.com/apk/res/cv.yyh.com.myscrollbarlistview"
    android:layout_height="match_parent">
    <cv.yyh.com.myscrollbarlistview.view.MyScrollbarListview
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:choiceMode="singleChoice"
        android:scrollbarThumbVertical="@drawable/listbar"
        android:id="@+id/lv_customser_zoomscroll"
        app:scrollBarPanel="@layout/panel_text"
        app:scrollBarComeInAnamation="@anim/transation_animation_left"
        app:scrollBarGoOutAnamation="@anim/transation_animation_right"
        />
</LinearLayout>

其他代码详见源码地址:https://github.com/androidstarjack/MyScrllBarListView

源码已上传GitHub 连接地址:

https://github.com/androidstarjack/MyScrllBarListView

androidStarjack的博客地址:

http://blog.csdn.net/androidstarjack/article/details/69085140

如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809   

微信公众号:终端研发部

Markdown

(欢迎关注学习和交流)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

androidstarjack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值