WheelView滚轮思路学习

为了理解WheelView滚轮实现效果,我按照WheelView源码简单的依样画葫芦。

某些关键的计算:

1,滑动偏移量

2.显示的范围ItemsRange,这个非常关键,移除Item,跟新增Item需要这个范围

private ItemsRange getItemsRange() {
        if (getItemHeight() == 0) {
            return null;
        }

        int first = currentItem;
        int count = 1;

        while (count * getItemHeight() < getHeight()) {
            first--;
            count += 2; // top + bottom items
        }
        return new ItemsRange(first, count);
    }

3.LinearLayout布中显示

   private void drawItems(Canvas canvas) {
        canvas.save();
        int top = (currentItem - firstItem) * getItemHeight() + (getItemHeight() - getHeight()) / 2;//第一个Item的位置
        canvas.translate(PADDING, -top + scrollingOffset);//画布原点。
        itemsLayout.draw(canvas);
        canvas.restore();
    }


理解WheelView开源源码的实现思路:

1.自定义View---WheelView,通过Canvas画出一个LinearLayout的内容,能正确把Linearlayout显示出来,完成第一步。

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        itemsLayout.draw(canvas);
        canvas.restore();
    }

    @Override
    public void layout(int l, int t, int r, int b) {
        super.layout(l, t, r, b);
        itemsLayout.layout(0, 0, itemsWidth, height);
    }

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        Log.d("uuu10","onMeasure");
        buildViewForMeasuring();//增删LinearLaout中的子类

        int width = calculateLayoutWidth(widthSize, widthMode);

        int height;
        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            height = getDesiredHeight(itemsLayout);
            if (heightMode == MeasureSpec.AT_MOST) {
                height = Math.min(height, heightSize);
            }
        }
        setMeasuredDimension(width, height);
        Log.d("uuu", "onMeasure" + itemsLayout.getChildCount());
    }

2.通过Touch事件(使用源码的WheelScroller辅助类)让LinearLaout移动,且每超过一个子类的高度就重设scrollingOffset,并计算移动的Item数量

    @Override
    public void onScroll(int distance) {
        scrollingOffset += distance;
        int itemHeight = getItemHeight();
        int count = scrollingOffset / itemHeight;
        int fixPos = scrollingOffset % itemHeight;
        scrollingOffset = fixPos;
    }

3.通过ItemsRange的范围更新Linear Layout的内容,增删Linear Layout子类。如果Linear Layout有增删子类的话,需要重新 layout 与measure

    private void updateView() {
        if (rebuildItems()) {
            calculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY);
            layout(getWidth(), getHeight());
        }
    }
<pre name="code" class="html"> private boolean rebuildItems() {
        boolean updated = false;
        ItemsRange range = getItemsRange();
        if (itemsLayout != null) {
<span style="white-space:pre">	</span>    //移除不在Range中的view
            int first = recycleItems(itemsLayout, firstItem, range);
            updated = firstItem != first;
            firstItem = first;
        } else {
            createItemsLayout();
            updated = true;
        }

        if (!updated) {
            updated = firstItem != range.getFirst() || itemsLayout.getChildCount() != range.getCount();
        }

        //firstItem在可视范围中
        if (firstItem > range.getFirst() && firstItem <= range.getLast()) {
            for (int i = firstItem - 1; i >= range.getFirst(); i--) {
                if (!addViewItem(i, true)) {
                    break;
                }

                firstItem = i;
            }
        } else {
            firstItem = range.getFirst();
        }
        //不在可视范围
        int first = firstItem;
        for (int i = itemsLayout.getChildCount(); i < range.getCount(); i++) {
            if (!addViewItem(firstItem + i, false) && itemsLayout.getChildCount() == 0) {
                first++;
            }
        }
        firstItem = first;
        Log.d("uuu", "visibleItems=" + visibleItems + " firstItem=" + firstItem + " itemsLayout.getChildCount()= " + itemsLayout.getChildCount());

        return updated;
    }


 4.滑动结束后,调整Item位置 

    @Override
    public void onJustify() {
        if (Math.abs(scrollingOffset) > WheelScroller.MIN_DELTA_FOR_SCROLLING) {
            mScroller.scroll(scrollingOffset, 0);
        }
    }


Wheel类的整个流程:

1.初始化:onMeasue --> layout --> buildViewForMeasureing --> onDraw--->updateView

buildViewForMeasureing --- 初始化linearLayout 内容

onDraw --- 画linearLayout  的Canvas

2.滑动的时候:onScroll-->invalidate-->onDraw--->updateview --->recycleItems(如果内容变化--->linearLayout layout).--->onJustify

onScroll--- 设置偏移量,与当前位置currentItem.

invalidate----滑动的后刷新

onDraw----画linearLayout 的最新位置

updateview----

recycleItems----获取ItemsRange,移除已出ItemsRange的View,再增加进入ItemsRange的View


源码:http://download.csdn.net/detail/lzo4a/9606895


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值