Android中WheelView代码分析笔记1(明天继续分析 >>>>>)

来源:互联网 发布:js用函数做n的阶乘 编辑:程序博客网 时间:2024/05/17 01:39
package com.guozg.wheelview.views;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.graphics.drawable.GradientDrawable;import android.graphics.drawable.GradientDrawable.Orientation;import android.os.Handler;import android.os.Message;import android.text.Layout;import android.text.StaticLayout;import android.text.TextPaint;import android.util.AttributeSet;import android.util.FloatMath;import android.view.GestureDetector;import android.view.GestureDetector.SimpleOnGestureListener;import android.view.MotionEvent;import android.view.View;import android.view.animation.Interpolator;import android.widget.Scroller;import com.guozg.wheelview.R;import java.util.LinkedList;import java.util.List;/** * Numeric wheel view. */public class WheelView extends View {    /**     * Scrolling duration     */    private static final int SCROLLING_DURATION = 400;    /**     * Minimum delta for scrolling     */    private static final int MIN_DELTA_FOR_SCROLLING = 1; //判断是否需要滚动调整的误差值    /**     * 选中项的颜色值     */    private static final int VALUE_TEXT_COLOR = 0xFFFF0000;    /**     * 未选中项的颜色值     */    private static final int ITEMS_TEXT_COLOR = 0xFF000000;    /**     * 顶部和底部的阴影     */    private static final int[] SHADOWS_COLORS = new int[]{0xFF111111, 0x00AAAAAA, 0x00AAAAAA};    /**     * 额外的列表项 高度 是加到标准的列表项高度上去的     */    private static final int ADDITIONAL_ITEM_HEIGHT = 15;    /**     * Text size     */    private static final int TEXT_SIZE = 24;    /**     * 顶部和底部的偏移量 用来隐藏     */    private static final int ITEM_OFFSET = TEXT_SIZE / 5;    /**     * item 额外添加的高度     */    private static final int ADDITIONAL_ITEMS_SPACE = 10;    /**     * Label offset     */    private static final int LABEL_OFFSET = 8;    /**     * 左右两边的padding值     */    private static final int PADDING = 10;    /**     * 默认的可见item个数     */    private static final int DEF_VISIBLE_ITEMS = 5;    // Messages    private final int MESSAGE_SCROLL = 0; //滚动    private final int MESSAGE_JUSTIFY = 1; //调整    // Cyclic    boolean isCyclic = false;    // Wheel Values    private WheelAdapter adapter = null;    private int currentItem = 0;    // Widths    private int itemsWidth = 0;    private int labelWidth = 0;    // Count of visible items    private int visibleItems = DEF_VISIBLE_ITEMS;    //StaticLayout 解析 : 该组件用于显示文本,    // 一旦该文本被显示后, 就不能再编辑, 如果想要修改文本, 使用 DynamicLayout 布局即可;    // Item height  item的高度    private int itemHeight = 0;    // Text paints    private TextPaint itemsPaint; //普通文字画笔    private TextPaint valuePaint;//选中文字的画笔  >>>>肯定是字体颜色突出一点咯 字体大一点什么的    //使用场景 : 一般情况下不会使用该组件, 当想要自定义组件 或者 想要使用 Canvas 绘制文本时 才使用该布局;    private StaticLayout itemsLayout; //普通条目布局    private StaticLayout labelLayout;//选中条目布局    private StaticLayout valueLayout;//标签布局  >>>>没看作用 目前    // Label & background    private String label;    private Drawable centerDrawable;  //选中条的背景    // //渐变的Drawable 我们经常在 drawable是用的shape中gradient的属性 >>相对应    private GradientDrawable topShadow; //头部的 >>这两个应该是相反    private GradientDrawable bottomShadow;//底部的    // Scrolling    private boolean isScrollingPerformed; //是否正在执行 滚动 动作    private int scrollingOffset; //滚动中的偏移量    // Scrolling animation    private GestureDetector gestureDetector; //手势    private Scroller scroller; //用于 平滑滚动的    private int lastScrollY;    // Listeners >>>>>>>>>>>>>>>>>>  可以设置多个监听器    private List<OnWheelChangedListener> changingListeners = new LinkedList<OnWheelChangedListener>();    private List<OnWheelScrollListener> scrollingListeners = new LinkedList<OnWheelScrollListener>();    // animation handler    private Handler animationHandler = new Handler() {        public void handleMessage(Message msg) {            scroller.computeScrollOffset(); //返回值为boolean,true说明滚动尚未完成,            // false说明滚动已经完成。这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。            //            int currY = scroller.getCurrY();            int delta = lastScrollY - currY;            lastScrollY = currY;            if (delta != 0) {                doScroll(delta);            }            //当滚动到对应的位置的时候 ,Scroller的状态还没有改变 所以需要我们去手动的结束 最后的滚动            if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {                currY = scroller.getFinalY();                scroller.forceFinished(true);            }            if (!scroller.isFinished()) { //如果还是没有停止 继续请求 >>>                animationHandler.sendEmptyMessage(msg.what); //>>>继续回调 >>>完成动画            } else if (msg.what == MESSAGE_SCROLL) {                justify(); //如果 动画已经停止 就 微调一下             } else {                finishScrolling();            }        }    };    // gesture listener    private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {        public boolean onDown(MotionEvent e) {            if (isScrollingPerformed) {                scroller.forceFinished(true);                clearMessages();                return true;            }            return false;        }        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {            startScrolling();            doScroll((int) -distanceY);            return true;        }        /**         *         * @param e1         * @param e2         * @param velocityX         * @param velocityY         * @return         */        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {            lastScrollY = currentItem * getItemHeight() + scrollingOffset;            int maxY = isCyclic ? 0x7FFFFFFF : adapter.getItemsCount() * getItemHeight();            int minY = isCyclic ? -maxY : 0;            scroller.fling(0, lastScrollY, 0, (int) -velocityY / 2, 0, 0, minY, maxY);            setNextMessage(MESSAGE_SCROLL);            return true;        }    };    /**     * Constructor     */    public WheelView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        initData(context);    }    /**     * Constructor     */    public WheelView(Context context, AttributeSet attrs) {        super(context, attrs);        initData(context);    }    /**     * Constructor     */    public WheelView(Context context) {        super(context);        initData(context);    }    /**     * Initializes class data     *     * @param context the context     */    private void initData(Context context) {        gestureDetector = new GestureDetector(context, gestureListener); //初始化手势监听器        gestureDetector.setIsLongpressEnabled(false); //长按        scroller = new Scroller(context); //初始化 滑动    }    /**     * Gets wheel adapter     *     * @return the adapter     */    public WheelAdapter getAdapter() {        return adapter;    }    /**     * Sets wheel adapter     *     * @param adapter the new wheel adapter     */    public void setAdapter(WheelAdapter adapter) {        this.adapter = adapter;        invalidateLayouts(); //刷新布局        invalidate(); //重绘    }    /**     * Set the the specified scrolling interpolator     * <p/>     * 设置指定的滚动插值器     *     * @param interpolator the interpolator     */    public void setInterpolator(Interpolator interpolator) {        scroller.forceFinished(true); //强制关闭当前的滚动  新创建一个有 插值器的        scroller = new Scroller(getContext(), interpolator);    }    /**     * Gets count of visible items     *     * @return the count of visible items     */    public int getVisibleItems() {        return visibleItems;    }    /**     * Sets count of visible items     *     * @param count the new count     */    public void setVisibleItems(int count) {        visibleItems = count;        invalidate();    }    /**     * Gets label     *     * @return the label     */    public String getLabel() {        return label;    }    /**     * Sets label     *     * @param newLabel the label to set     */    public void setLabel(String newLabel) {        if (label == null || !label.equals(newLabel)) {            label = newLabel;            labelLayout = null;            invalidate();        }    }    /**     * Adds wheel changing listener     *     * @param listener the listener     */    public void addChangingListener(OnWheelChangedListener listener) {        changingListeners.add(listener);    }    /**     * Removes wheel changing listener     *     * @param listener the listener     */    public void removeChangingListener(OnWheelChangedListener listener) {        changingListeners.remove(listener);    }    /**     * Notifies changing listeners     *     * @param oldValue the old wheel value     * @param newValue the new wheel value     */    protected void notifyChangingListeners(int oldValue, int newValue) {        for (OnWheelChangedListener listener : changingListeners) {            listener.onChanged(this, oldValue, newValue); //去通知 数据 改变        }    }    /**     * Adds wheel scrolling listener     *     * @param listener the listener     */    public void addScrollingListener(OnWheelScrollListener listener) {        scrollingListeners.add(listener);    }    /**     * Removes wheel scrolling listener     *     * @param listener the listener     */    public void removeScrollingListener(OnWheelScrollListener listener) {        scrollingListeners.remove(listener);    }    /**     * Notifies listeners about starting scrolling     */    protected void notifyScrollingListenersAboutStart() {        for (OnWheelScrollListener listener : scrollingListeners) {            listener.onScrollingStarted(this);        }    }    /**     * Notifies listeners about ending scrolling     */    protected void notifyScrollingListenersAboutEnd() {        for (OnWheelScrollListener listener : scrollingListeners) {            listener.onScrollingFinished(this); //通知滚动事件        }    }    /**     * Gets current value     *     * @return the current value     */    public int getCurrentItem() {        return currentItem;    }    /**     * Sets the current item w/o animation. Does nothing when index is wrong.     *     * @param index the item index     */    public void setCurrentItem(int index) {        setCurrentItem(index, false);    }    /**     * 设置当前选中项 如果 下标异常 直接不处理 如果下标 正常     * 判断是否需要动画效果     * 如果 需要 就使用scroller平滑的滑动过去     * 如果 不需要就使界面失效 直接重绘 界面     *     * @param index    需要设置的下标     * @param animated 是否需要动画的标志     */    public void setCurrentItem(int index, boolean animated) {        if (adapter == null || adapter.getItemsCount() == 0) {            return; // throw?        }        if (index < 0 || index >= adapter.getItemsCount()) {            if (isCyclic) {  //如果 是循环 那么 就不算 越界  做个 判断 就能求出来 位置                while (index < 0) {                    index += adapter.getItemsCount();                }                index %= adapter.getItemsCount();            } else { //如果是不能循环 那就是错误的下标                return; // throw?            }        }        if (index != currentItem) {  //如果 设置 不是 当前 一致  就需要跳转 到  友好界面 滑过去            if (animated) {  //是否是有动画效果 有 就滑过去                scroll(index - currentItem, SCROLLING_DURATION);            } else {                //没有 直接使得界面失效 得了                invalidateLayouts();                //顺便 通知一下 改变了 数据哦  把 就数据 和新数据的下标 传递过去                int old = currentItem;                currentItem = index;                notifyChangingListeners(old, currentItem);                invalidate(); //直接重绘            }        }    }    /**     * Tests if wheel is cyclic. That means before the 1st item there is shown     * the last one     *     * @return true if wheel is cyclic     */    public boolean isCyclic() {        return isCyclic;    }    /**     * Set wheel cyclic flag     *     * @param isCyclic the flag to set     */    public void setCyclic(boolean isCyclic) {        this.isCyclic = isCyclic;        invalidate();        invalidateLayouts();    }    /**     * Invalidates layouts     */    private void invalidateLayouts() {        itemsLayout = null;        valueLayout = null;        scrollingOffset = 0;    }    /**     * Initializes resources     */    private void initResourcesIfNecessary() {        if (itemsPaint == null) { //普通项的画笔            itemsPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FAKE_BOLD_TEXT_FLAG);            // itemsPaint.density = getResources().getDisplayMetrics().density;            itemsPaint.setTextSize(TEXT_SIZE);        }        if (valuePaint == null) { //选中项的画笔            valuePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FAKE_BOLD_TEXT_FLAG | Paint.DITHER_FLAG);            // valuePaint.density = getResources().getDisplayMetrics().density;            valuePaint.setTextSize(TEXT_SIZE);            valuePaint.setShadowLayer(0.1f, 0, 0.1f, 0xFFC0C0C0);        }        //获取列表重心的 背景        if (centerDrawable == null) {            centerDrawable = getContext().getResources().getDrawable(R.drawable.wheel_val);        }        //恰好相反 >>>>为了 突出中心  中间 一个颜色 上下一一致        if (topShadow == null) {            topShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS);        }        if (bottomShadow == null) {            bottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS);        }        setBackgroundResource(R.drawable.wheel_bg);    }    /**     * 计算出 布局想要的高度     *     * @param layout 传入的是想要 进行计算的布局     * @return 返回该布局想要的高度     */    private int getDesiredHeight(Layout layout) {        if (layout == null) {            return 0;        }        int desired = getItemHeight() * visibleItems - ITEM_OFFSET * 2 - ADDITIONAL_ITEM_HEIGHT;        // Check against our minimum height        desired = Math.max(desired, getSuggestedMinimumHeight());        return desired;    }    /**     * 根据下标返回文本数据     *     * @param index the item index     * @return the item or null     */    private String getTextItem(int index) {        if (adapter == null || adapter.getItemsCount() == 0) {            return null;        }        int count = adapter.getItemsCount();        if ((index < 0 || index >= count) && !isCyclic) {            return null;        } else {            while (index < 0) {                index = count + index;            }        }        index %= count;        return adapter.getItem(index);    }    /**     * Builds text depending on current value     *     * @param useCurrentValue     * @return the text     */    private String buildText(boolean useCurrentValue) {        StringBuilder itemsText = new StringBuilder();        int addItems = visibleItems / 2 + 1;        for (int i = currentItem - addItems; i <= currentItem + addItems; i++) { //获取 当前屏幕的所有显示的文本            if (useCurrentValue || i != currentItem) { //正在 滚动 或者 不是当前选中的View的时候 >>>>.这里已经过滤掉了选中状态下的当前Item的相应文本                String text = getTextItem(i);                if (text != null) {                    itemsText.append(text);                }            }            if (i < currentItem + addItems) {                itemsText.append("\n");            }        }        return itemsText.toString();    }    /**     * 返回 最大的文本 宽度 是的 可以完整的呈现出来     *     * @return the max length     */    private int getMaxTextLength() {        WheelAdapter adapter = getAdapter();        if (adapter == null) {            return 0;        }        int adapterLength = adapter.getMaximumLength();        if (adapterLength > 0) { //如果是已经重写了该方法的适配器 应该是可以获取的            return adapterLength;        }        //下面是针对 没有 重写适配器中的该方法的情况        String maxText = null;        int addItems = visibleItems / 2; //求出 课件项的重点        //对所有 可见item 进行 便利 取出 最长字符串        for (int i = Math.max(currentItem - addItems, 0);  //第一个可见             i < Math.min(currentItem + visibleItems,//最后一个课件                     adapter.getItemsCount()); i++) { //遍历            String text = adapter.getItem(i); //获取文本            if (text != null && (maxText == null || maxText.length() < text.length())) {                maxText = text;            }        }        return maxText != null ? maxText.length() : 0; //返回最大高度    }    /**     * Returns height of wheel item     *     * @return the item height     */    private int getItemHeight() {        if (itemHeight != 0) {            return itemHeight;        } else if (itemsLayout != null && itemsLayout.getLineCount() > 2) {            itemHeight = itemsLayout.getLineTop(2) - itemsLayout.getLineTop(1);            return itemHeight;        }        return getHeight() / visibleItems;    }    /**     * Calculates control width and creates text layouts     *     * @param widthSize the input layout width     * @param mode      the layout mode     * @return the calculated control width     */    private int calculateLayoutWidth(int widthSize, int mode) {        initResourcesIfNecessary();        int width = widthSize;        int maxLength = getMaxTextLength();        if (maxLength > 0) {            float textWidth = FloatMath.ceil(Layout.getDesiredWidth("0", itemsPaint));            itemsWidth = (int) (maxLength * textWidth);        } else {            itemsWidth = 0;        }        itemsWidth += ADDITIONAL_ITEMS_SPACE; // make it some more        labelWidth = 0;        if (label != null && label.length() > 0) {            labelWidth = (int) FloatMath.ceil(Layout.getDesiredWidth(label, valuePaint));        }        boolean recalculate = false;        if (mode == MeasureSpec.EXACTLY) {            width = widthSize;            recalculate = true;        } else {            width = itemsWidth + labelWidth + 2 * PADDING;            if (labelWidth > 0) {                width += LABEL_OFFSET;            }            // Check against our minimum width            width = Math.max(width, getSuggestedMinimumWidth());            if (mode == MeasureSpec.AT_MOST && widthSize < width) {                width = widthSize;                recalculate = true;            }        }        if (recalculate) {            // recalculate width            int pureWidth = width - LABEL_OFFSET - 2 * PADDING;            if (pureWidth <= 0) {                itemsWidth = labelWidth = 0;            }            if (labelWidth > 0) {                double newWidthItems = (double) itemsWidth * pureWidth / (itemsWidth + labelWidth);                itemsWidth = (int) newWidthItems;                labelWidth = pureWidth - itemsWidth;            } else {                itemsWidth = pureWidth + LABEL_OFFSET; // no label            }        }        if (itemsWidth > 0) {            createLayouts(itemsWidth, labelWidth);        }        return width;    }    /**     * 创建布局     *     * @param widthItems width of items layout     * @param widthLabel width of label layout     */    private void createLayouts(int widthItems, int widthLabel) {        //如果还没有创建 或者是 当前的宽度 大于 所需要的 那么就进行重新创建        if (itemsLayout == null || itemsLayout.getWidth() > widthItems) {            // 1 显示文本            // 2画笔            // 3 文本宽度 ,            // 4对齐方式 ,            // 5行间距, 1f 代表 1 倍字体高度            // 6基础行距上增加多少 , 真实行间距 等于 spacingmult 和 spacingadd 的和            //7 不知道 false            //需要指出的是这个layout是默认画在Canvas的(0,0)点的,            // 如果需要调整位置只能在draw之前移Canvas的起始坐标canvas.translate(x, y);            itemsLayout = new StaticLayout(buildText(isScrollingPerformed), itemsPaint, widthItems,                    widthLabel > 0 ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER, 1,                    ADDITIONAL_ITEM_HEIGHT, false);        } else {            itemsLayout.increaseWidthTo(widthItems);        }        //下面画的选中的Item 同理        if (!isScrollingPerformed && (valueLayout == null || valueLayout.getWidth() > widthItems)) {//没有在滚动的时候 才有会选中项            String text = getAdapter() != null ? getAdapter().getItem(currentItem) : null;            valueLayout = new StaticLayout(text != null ? text : "", valuePaint, widthItems,                    widthLabel > 0 ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER, 1,                    ADDITIONAL_ITEM_HEIGHT, false);        } else if (isScrollingPerformed) { //正在滚动 那么显示选中的布局没有必要显示            valueLayout = null;        } else {            valueLayout.increaseWidthTo(widthItems);        }        if (widthLabel > 0) {            if (labelLayout == null || labelLayout.getWidth() > widthLabel) {                labelLayout = new StaticLayout(label, valuePaint, widthLabel, Layout.Alignment.ALIGN_NORMAL, 1,                        ADDITIONAL_ITEM_HEIGHT, false);            } else {                labelLayout.increaseWidthTo(widthLabel);            }        }    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        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);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        if (itemsLayout == null) {            if (itemsWidth == 0) {                calculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY);            } else {                createLayouts(itemsWidth, labelWidth);            }        }        if (itemsWidth > 0) {            canvas.save();            // Skip padding space and hide a part of top and bottom items            canvas.translate(PADDING, -ITEM_OFFSET); //平移画布            drawItems(canvas); //绘制 普通Item            drawValue(canvas); //绘制 选中Item            canvas.restore(); //把画布恢复        }        drawCenterRect(canvas);        drawShadows(canvas);    }    /**     * 绘制 顶部和底部的阴影     *     * @param canvas the canvas for drawing     */    private void drawShadows(Canvas canvas) {        topShadow.setBounds(0, 0, getWidth(), getHeight() / visibleItems);        topShadow.draw(canvas);        bottomShadow.setBounds(0, getHeight() - getHeight() / visibleItems, getWidth(), getHeight());        bottomShadow.draw(canvas);    }    /**     * Draws value and label layout     *     * @param canvas the canvas for drawing     */    private void drawValue(Canvas canvas) {        valuePaint.setColor(VALUE_TEXT_COLOR);        valuePaint.drawableState = getDrawableState();        Rect bounds = new Rect();        itemsLayout.getLineBounds(visibleItems / 2, bounds);        // draw label        if (labelLayout != null) {            canvas.save();            canvas.translate(itemsLayout.getWidth() + LABEL_OFFSET, bounds.top);            labelLayout.draw(canvas);            canvas.restore();        }        // 绘制选中的item        if (valueLayout != null) {            canvas.save();            canvas.translate(0, bounds.top + scrollingOffset);            valueLayout.draw(canvas);            canvas.restore();        }    }    /**     * 绘制普通Item     *     * @param canvas the canvas for drawing     */    private void drawItems(Canvas canvas) {        canvas.save();        int top = itemsLayout.getLineTop(1); //得到普通布局中的第一行的高度        canvas.translate(0, -top + scrollingOffset); //将画布平移上去之后 再空出一个添加的位置        itemsPaint.setColor(ITEMS_TEXT_COLOR);        itemsPaint.drawableState = getDrawableState();        itemsLayout.draw(canvas);        canvas.restore(); //恢复画布    }    /**     * 绘制空间中心的矩形局域     *     * @param canvas the canvas for drawing     */    private void drawCenterRect(Canvas canvas) {        int center = getHeight() / 2; //画布的中点        int offset = getItemHeight() / 2;  //列表项的宽度一半        centerDrawable.setBounds(0, center - offset, getWidth(), center + offset);        centerDrawable.draw(canvas);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        WheelAdapter adapter = getAdapter();        if (adapter == null) {            return true;        }        if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) {            //手指松开时和手势监听器,没有收到事件的时候            justify();        }        return true;    }    /**     * 滚动 这个 控件     *     * @param delta 需要滚动的距离     */    private void doScroll(int delta) {        scrollingOffset += delta;  //0+199  ing 199        int count = scrollingOffset / getItemHeight(); //需要滚动 的 item个数 因为 要恰好停在 item上 不能偏嘛 如果取证        int pos = currentItem - count;  //需要到达的位置        if (isCyclic && adapter.getItemsCount() > 0) {            // fix position by rotating 因为存在一个 可以循环 滑动 所以处理一下这种情况 做一下 位置判断            while (pos < 0) {                pos += adapter.getItemsCount();            }            pos %= adapter.getItemsCount();        } else if (isScrollingPerformed) { //是否正在滚动呢            //如果不是循环的            if (pos < 0) {  //如果是负的  最多滚动 当前个数的距离 -> 滚动 到 0                count = currentItem;                pos = 0;            } else if (pos >= adapter.getItemsCount()) { //如果要滚动的位置大于最多的位置                count = currentItem - adapter.getItemsCount() + 1;                pos = adapter.getItemsCount() - 1;            }        } else {            // fix position  防止越界            pos = Math.max(pos, 0); //保证 位置 大于0            pos = Math.min(pos, adapter.getItemsCount() - 1); //保证 位置 小于 最大的        }        int offset = scrollingOffset;        if (pos != currentItem) {            setCurrentItem(pos, false);        } else {            invalidate();        }        // update offset        scrollingOffset = offset - count * getItemHeight();  //恰好滚动的距离 可以使得 恰好在中间        if (scrollingOffset > getHeight()) {  //去除了重复的次数            scrollingOffset = scrollingOffset % getHeight() + getHeight();        }    }    /**     * 先清空消息队列的所有信息 再将信息传递过去     *     * @param message the message to set     */    private void setNextMessage(int message) {        clearMessages();        animationHandler.sendEmptyMessage(message);    }    /**     * 将消息队列中过的信息进行清空处理     */    private void clearMessages() {        animationHandler.removeMessages(MESSAGE_SCROLL);        animationHandler.removeMessages(MESSAGE_JUSTIFY);    }    /**     * Justifies wheel  整理版面 >>>>>>>>>>>>>     */    private void justify() {        if (adapter == null) {            return;        }        lastScrollY = 0;        int offset = scrollingOffset;        int itemHeight = getItemHeight();        //判断是否 需要去 微调 使得恰好 落在中间        boolean needToIncrease = offset > 0 ? currentItem < adapter.getItemsCount() : currentItem > 0;        //如果是循环的或者是不循环但是也是可以调整的状态        if ((isCyclic || needToIncrease) && Math.abs((float) offset) > (float) itemHeight / 2) {            if (offset < 0) //                offset += itemHeight + MIN_DELTA_FOR_SCROLLING;            else                offset -= itemHeight + MIN_DELTA_FOR_SCROLLING;        }        if (Math.abs(offset) > MIN_DELTA_FOR_SCROLLING) {            //最后 滚动一丢丢            scroller.startScroll(0, 0, 0, offset, SCROLLING_DURATION);            //通知一下 动画控制器            setNextMessage(MESSAGE_JUSTIFY);        } else {            //不需要调整 可以有            finishScrolling();        }    }    /**     * 开始滚动调用 开始滚动的方法     */    private void startScrolling() {        if (!isScrollingPerformed) {            isScrollingPerformed = true;            notifyScrollingListenersAboutStart();        }    }    /**     * 停止 滚动 调用停止滚动的方法     */    void finishScrolling() {        if (isScrollingPerformed) {            notifyScrollingListenersAboutEnd();            isScrollingPerformed = false;        }        invalidateLayouts();        invalidate();    }    /**     * Scroll the wheel     *     * @param     * @param time scrolling duration     */    public void scroll(int itemsToScroll, int time) {        scroller.forceFinished(true); //强制关了        lastScrollY = scrollingOffset;        int offset = itemsToScroll * getItemHeight();        scroller.startScroll(0, lastScrollY, 0, offset - lastScrollY, time); //平滑滚动        setNextMessage(MESSAGE_SCROLL); //通知去微调        startScrolling(); //通知一下 开始 滚动 相关的监听器得知道吧    }}
0 0
原创粉丝点击