android仿iPhone滚轮控件实现及源码分析(二)

  在上一篇android仿iPhone滚轮控件实现及源码分析(一)简单的说了下架构还有效果图,但是关于图形的绘制各方面的代码在532行到940行,如果写在一篇文章里面,可能会导致文章太长,效果不好,所以自作聪明的分成了两篇大笑。闲言碎语不要讲,下面开始正事。

       首先,先把代码贴出来:

[java]  view plain copy
  1. /** 
  2.      * Calculates control width and creates text layouts 
  3.      * @param widthSize the input layout width 
  4.      * @param mode the layout mode 
  5.      * @return the calculated control width 
  6.      */  
  7.     private int calculateLayoutWidth(int widthSize, int mode) {  
  8.         initResourcesIfNecessary();  
  9.   
  10.         int width = widthSize;  
  11.         int maxLength = getMaxTextLength();  
  12.         if (maxLength > 0) {  
  13.             float textWidth = FloatMath.ceil(Layout.getDesiredWidth("0", itemsPaint));  
  14.             itemsWidth = (int) (maxLength * textWidth);  
  15.         } else {  
  16.             itemsWidth = 0;  
  17.         }  
  18.         itemsWidth += ADDITIONAL_ITEMS_SPACE; // make it some more  
  19.   
  20.         labelWidth = 0;  
  21.         if (label != null && label.length() > 0) {  
  22.             labelWidth = (int) FloatMath.ceil(Layout.getDesiredWidth(label, valuePaint));  
  23.         }  
  24.   
  25.         boolean recalculate = false;  
  26.         if (mode == MeasureSpec.EXACTLY) {  
  27.             width = widthSize;  
  28.             recalculate = true;  
  29.         } else {  
  30.             width = itemsWidth + labelWidth + 2 * PADDING;  
  31.             if (labelWidth > 0) {  
  32.                 width += LABEL_OFFSET;  
  33.             }  
  34.   
  35.             // Check against our minimum width  
  36.             width = Math.max(width, getSuggestedMinimumWidth());  
  37.   
  38.             if (mode == MeasureSpec.AT_MOST && widthSize < width) {  
  39.                 width = widthSize;  
  40.                 recalculate = true;  
  41.             }  
  42.         }  
  43.   
  44.         if (recalculate) {  
  45.             // recalculate width  
  46.             int pureWidth = width - LABEL_OFFSET - 2 * PADDING;  
  47.             if (pureWidth <= 0) {  
  48.                 itemsWidth = labelWidth = 0;  
  49.             }  
  50.             if (labelWidth > 0) {  
  51.                 double newWidthItems = (double) itemsWidth * pureWidth  
  52.                         / (itemsWidth + labelWidth);  
  53.                 itemsWidth = (int) newWidthItems;  
  54.                 labelWidth = pureWidth - itemsWidth;  
  55.             } else {  
  56.                 itemsWidth = pureWidth + LABEL_OFFSET; // no label  
  57.             }  
  58.         }  
  59.   
  60.         if (itemsWidth > 0) {  
  61.             createLayouts(itemsWidth, labelWidth);  
  62.         }  
  63.   
  64.         return width;  
  65.     }  
  66.   
  67.     /** 
  68.      * Creates layouts 
  69.      * @param widthItems width of items layout 
  70.      * @param widthLabel width of label layout 
  71.      */  
  72.     private void createLayouts(int widthItems, int widthLabel) {  
  73.         if (itemsLayout == null || itemsLayout.getWidth() > widthItems) {  
  74.             itemsLayout = new StaticLayout(buildText(isScrollingPerformed), itemsPaint, widthItems,  
  75.                     widthLabel > 0 ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER,  
  76.                     1, ADDITIONAL_ITEM_HEIGHT, false);  
  77.         } else {  
  78.             itemsLayout.increaseWidthTo(widthItems);  
  79.         }  
  80.   
  81.         if (!isScrollingPerformed && (valueLayout == null || valueLayout.getWidth() > widthItems)) {  
  82.             String text = getAdapter() != null ? getAdapter().getItem(currentItem) : null;  
  83.             valueLayout = new StaticLayout(text != null ? text : "",  
  84.                     valuePaint, widthItems, widthLabel > 0 ?  
  85.                             Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER,  
  86.                             1, ADDITIONAL_ITEM_HEIGHT, false);  
  87.         } else if (isScrollingPerformed) {  
  88.             valueLayout = null;  
  89.         } else {  
  90.             valueLayout.increaseWidthTo(widthItems);  
  91.         }  
  92.   
  93.         if (widthLabel > 0) {  
  94.             if (labelLayout == null || labelLayout.getWidth() > widthLabel) {  
  95.                 labelLayout = new StaticLayout(label, valuePaint,  
  96.                         widthLabel, Layout.Alignment.ALIGN_NORMAL, 1,  
  97.                         ADDITIONAL_ITEM_HEIGHT, false);  
  98.             } else {  
  99.                 labelLayout.increaseWidthTo(widthLabel);  
  100.             }  
  101.         }  
  102.     }  
  103.   
  104.     @Override  
  105.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  106.         int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
  107.         int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
  108.         int widthSize = MeasureSpec.getSize(widthMeasureSpec);  
  109.         int heightSize = MeasureSpec.getSize(heightMeasureSpec);  
  110.   
  111.         int width = calculateLayoutWidth(widthSize, widthMode);  
  112.   
  113.         int height;  
  114.         if (heightMode == MeasureSpec.EXACTLY) {  
  115.             height = heightSize;  
  116.         } else {  
  117.             height = getDesiredHeight(itemsLayout);  
  118.   
  119.             if (heightMode == MeasureSpec.AT_MOST) {  
  120.                 height = Math.min(height, heightSize);  
  121.             }  
  122.         }  
  123.   
  124.         setMeasuredDimension(width, height);  
  125.     }  
  126.   
  127.     @Override  
  128.     protected void onDraw(Canvas canvas) {  
  129.         super.onDraw(canvas);  
  130.           
  131.         if (itemsLayout == null) {  
  132.             if (itemsWidth == 0) {  
  133.                 calculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY);  
  134.             } else {  
  135.                 createLayouts(itemsWidth, labelWidth);  
  136.             }  
  137.         }  
  138.   
  139.         if (itemsWidth > 0) {  
  140.             canvas.save();  
  141.             // Skip padding space and hide a part of top and bottom items  
  142.             canvas.translate(PADDING, -ITEM_OFFSET);  
  143.             drawItems(canvas);  
  144.             drawValue(canvas);  
  145.             canvas.restore();  
  146.         }  
  147.   
  148.         drawCenterRect(canvas);  
  149.         drawShadows(canvas);  
  150.     }  
  151.   
  152.     /** 
  153.      * Draws shadows on top and bottom of control 
  154.      * @param canvas the canvas for drawing 
  155.      */  
  156.     private void drawShadows(Canvas canvas) {  
  157.         topShadow.setBounds(00, getWidth(), getHeight() / visibleItems);  
  158.         topShadow.draw(canvas);  
  159.   
  160.         bottomShadow.setBounds(0, getHeight() - getHeight() / visibleItems,  
  161.                 getWidth(), getHeight());  
  162.         bottomShadow.draw(canvas);  
  163.     }  
  164.   
  165.     /** 
  166.      * Draws value and label layout 
  167.      * @param canvas the canvas for drawing 
  168.      */  
  169.     private void drawValue(Canvas canvas) {  
  170.         valuePaint.setColor(VALUE_TEXT_COLOR);  
  171.         valuePaint.drawableState = getDrawableState();  
  172.   
  173.         Rect bounds = new Rect();  
  174.         itemsLayout.getLineBounds(visibleItems / 2, bounds);  
  175.   
  176.         // draw label  
  177.         if (labelLayout != null) {  
  178.             canvas.save();  
  179.             canvas.translate(itemsLayout.getWidth() + LABEL_OFFSET, bounds.top);  
  180.             labelLayout.draw(canvas);  
  181.             canvas.restore();  
  182.         }  
  183.   
  184.         // draw current value  
  185.         if (valueLayout != null) {  
  186.             canvas.save();  
  187.             canvas.translate(0, bounds.top + scrollingOffset);  
  188.             valueLayout.draw(canvas);  
  189.             canvas.restore();  
  190.         }  
  191.     }  
  192.   
  193.     /** 
  194.      * Draws items 
  195.      * @param canvas the canvas for drawing 
  196.      */  
  197.     private void drawItems(Canvas canvas) {  
  198.         canvas.save();  
  199.           
  200.         int top = itemsLayout.getLineTop(1);  
  201.         canvas.translate(0, - top + scrollingOffset);  
  202.           
  203.         itemsPaint.setColor(ITEMS_TEXT_COLOR);  
  204.         itemsPaint.drawableState = getDrawableState();  
  205.         itemsLayout.draw(canvas);  
  206.           
  207.         canvas.restore();  
  208.     }  
  209.   
  210.     /** 
  211.      * Draws rect for current value 
  212.      * @param canvas the canvas for drawing 
  213.      */  
  214.     private void drawCenterRect(Canvas canvas) {  
  215.         int center = getHeight() / 2;  
  216.         int offset = getItemHeight() / 2;  
  217.         centerDrawable.setBounds(0, center - offset, getWidth(), center + offset);  
  218.         centerDrawable.draw(canvas);  
  219.     }  
  220.   
  221.     @Override  
  222.     public boolean onTouchEvent(MotionEvent event) {  
  223.         WheelAdapter adapter = getAdapter();  
  224.         if (adapter == null) {  
  225.             return true;  
  226.         }  
  227.           
  228.             if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) {  
  229.             justify();  
  230.         }  
  231.         return true;  
  232.     }  
  233.       
  234.     /** 
  235.      * Scrolls the wheel 
  236.      * @param delta the scrolling value 
  237.      */  
  238.     private void doScroll(int delta) {  
  239.         scrollingOffset += delta;  
  240.           
  241.         int count = scrollingOffset / getItemHeight();  
  242.         int pos = currentItem - count;  
  243.         if (isCyclic && adapter.getItemsCount() > 0) {  
  244.             // fix position by rotating  
  245.             while (pos < 0) {  
  246.                 pos += adapter.getItemsCount();  
  247.             }  
  248.             pos %= adapter.getItemsCount();  
  249.         } else if (isScrollingPerformed) {  
  250.             //   
  251.             if (pos < 0) {  
  252.                 count = currentItem;  
  253.                 pos = 0;  
  254.             } else if (pos >= adapter.getItemsCount()) {  
  255.                 count = currentItem - adapter.getItemsCount() + 1;  
  256.                 pos = adapter.getItemsCount() - 1;  
  257.             }  
  258.         } else {  
  259.             // fix position  
  260.             pos = Math.max(pos, 0);  
  261.             pos = Math.min(pos, adapter.getItemsCount() - 1);  
  262.         }  
  263.           
  264.         int offset = scrollingOffset;  
  265.         if (pos != currentItem) {  
  266.             setCurrentItem(pos, false);  
  267.         } else {  
  268.             invalidate();  
  269.         }  
  270.           
  271.         // update offset  
  272.         scrollingOffset = offset - count * getItemHeight();  
  273.         if (scrollingOffset > getHeight()) {  
  274.             scrollingOffset = scrollingOffset % getHeight() + getHeight();  
  275.         }  
  276.     }  
  277.       
  278.     // gesture listener  
  279.     private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {  
  280.         public boolean onDown(MotionEvent e) {  
  281.             if (isScrollingPerformed) {  
  282.                 scroller.forceFinished(true);  
  283.                 clearMessages();  
  284.                 return true;  
  285.             }  
  286.             return false;  
  287.         }  
  288.           
  289.         public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {  
  290.             startScrolling();  
  291.             doScroll((int)-distanceY);  
  292.             return true;  
  293.         }  
  294.           
  295.         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {  
  296.             lastScrollY = currentItem * getItemHeight() + scrollingOffset;  
  297.             int maxY = isCyclic ? 0x7FFFFFFF : adapter.getItemsCount() * getItemHeight();  
  298.             int minY = isCyclic ? -maxY : 0;  
  299.             scroller.fling(0, lastScrollY, 0, (int) -velocityY / 200, minY, maxY);  
  300.             setNextMessage(MESSAGE_SCROLL);  
  301.             return true;  
  302.         }  
  303.     };  
  304.   
  305.     // Messages  
  306.     private final int MESSAGE_SCROLL = 0;  
  307.     private final int MESSAGE_JUSTIFY = 1;  
  308.       
  309.     /** 
  310.      * Set next message to queue. Clears queue before. 
  311.      *  
  312.      * @param message the message to set 
  313.      */  
  314.     private void setNextMessage(int message) {  
  315.         clearMessages();  
  316.         animationHandler.sendEmptyMessage(message);  
  317.     }  
  318.   
  319.     /** 
  320.      * Clears messages from queue 
  321.      */  
  322.     private void clearMessages() {  
  323.         animationHandler.removeMessages(MESSAGE_SCROLL);  
  324.         animationHandler.removeMessages(MESSAGE_JUSTIFY);  
  325.     }  
  326.       
  327.     // animation handler  
  328.     private Handler animationHandler = new Handler() {  
  329.         public void handleMessage(Message msg) {  
  330.             scroller.computeScrollOffset();  
  331.             int currY = scroller.getCurrY();  
  332.             int delta = lastScrollY - currY;  
  333.             lastScrollY = currY;  
  334.             if (delta != 0) {  
  335.                 doScroll(delta);  
  336.             }  
  337.               
  338.             // scrolling is not finished when it comes to final Y  
  339.             // so, finish it manually   
  340.             if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {  
  341.                 currY = scroller.getFinalY();  
  342.                 scroller.forceFinished(true);  
  343.             }  
  344.             if (!scroller.isFinished()) {  
  345.                 animationHandler.sendEmptyMessage(msg.what);  
  346.             } else if (msg.what == MESSAGE_SCROLL) {  
  347.                 justify();  
  348.             } else {  
  349.                 finishScrolling();  
  350.             }  
  351.         }  
  352.     };  
  353.       
  354.     /** 
  355.      * Justifies wheel 
  356.      */  
  357.     private void justify() {  
  358.         if (adapter == null) {  
  359.             return;  
  360.         }  
  361.           
  362.         lastScrollY = 0;  
  363.         int offset = scrollingOffset;  
  364.         int itemHeight = getItemHeight();  
  365.         boolean needToIncrease = offset > 0 ? currentItem < adapter.getItemsCount() : currentItem > 0;   
  366.         if ((isCyclic || needToIncrease) && Math.abs((float) offset) > (float) itemHeight / 2) {  
  367.             if (offset < 0)  
  368.                 offset += itemHeight + MIN_DELTA_FOR_SCROLLING;  
  369.             else  
  370.                 offset -= itemHeight + MIN_DELTA_FOR_SCROLLING;  
  371.         }  
  372.         if (Math.abs(offset) > MIN_DELTA_FOR_SCROLLING) {  
  373.             scroller.startScroll(000, offset, SCROLLING_DURATION);  
  374.             setNextMessage(MESSAGE_JUSTIFY);  
  375.         } else {  
  376.             finishScrolling();  
  377.         }  
  378.     }  
  379.       
  380.     /** 
  381.      * Starts scrolling 
  382.      */  
  383.     private void startScrolling() {  
  384.         if (!isScrollingPerformed) {  
  385.             isScrollingPerformed = true;  
  386.             notifyScrollingListenersAboutStart();  
  387.         }  
  388.     }  
  389.   
  390.     /** 
  391.      * Finishes scrolling 
  392.      */  
  393.     void finishScrolling() {  
  394.         if (isScrollingPerformed) {  
  395.             notifyScrollingListenersAboutEnd();  
  396.             isScrollingPerformed = false;  
  397.         }  
  398.         invalidateLayouts();  
  399.         invalidate();  
  400.     }  
  401.           
  402.     /** 
  403.      * Scroll the wheel 
  404.      * @param itemsToSkip items to scroll 
  405.      * @param time scrolling duration 
  406.      */  
  407.     public void scroll(int itemsToScroll, int time) {  
  408.         scroller.forceFinished(true);  
  409.         lastScrollY = scrollingOffset;  
  410.         int offset = itemsToScroll * getItemHeight();         
  411.         scroller.startScroll(0, lastScrollY, 0, offset - lastScrollY, time);  
  412.         setNextMessage(MESSAGE_SCROLL);       
  413.         startScrolling();  
  414.     }  

         在629行到744行的代码是绘制图形,747行onTouchEvent()里面主要是调用了882行的justify()方法,用于调整画面,

[java]  view plain copy
  1. @Override  
  2.     public boolean onTouchEvent(MotionEvent event) {  
  3.         WheelAdapter adapter = getAdapter();  
  4.         if (adapter == null) {  
  5.             return true;  
  6.         }  
  7.           
  8.             if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) {  
  9.             justify();  
  10.         }  
  11.         return true;  
  12.     }  


[java]  view plain copy
  1. /** 
  2.      * Justifies wheel 
  3.      */  
  4.     private void justify() {  
  5.         if (adapter == null) {  
  6.             return;  
  7.         }  
  8.           
  9.         lastScrollY = 0;  
  10.         int offset = scrollingOffset;  
  11.         int itemHeight = getItemHeight();  
  12.         boolean needToIncrease = offset > 0 ? currentItem < adapter.getItemsCount() : currentItem > 0;   
  13.         if ((isCyclic || needToIncrease) && Math.abs((float) offset) > (float) itemHeight / 2) {  
  14.             if (offset < 0)  
  15.                 offset += itemHeight + MIN_DELTA_FOR_SCROLLING;  
  16.             else  
  17.                 offset -= itemHeight + MIN_DELTA_FOR_SCROLLING;  
  18.         }  
  19.         if (Math.abs(offset) > MIN_DELTA_FOR_SCROLLING) {  
  20.             scroller.startScroll(000, offset, SCROLLING_DURATION);  
  21.             setNextMessage(MESSAGE_JUSTIFY);  
  22.         } else {  
  23.             finishScrolling();  
  24.         }  
  25.     }  

         我们看下重写的系统回调函数onMeasure()(用于测量各个控件距离,父子控件空间大小等):

[java]  view plain copy
  1. @Override  
  2.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  3.         int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
  4.         int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
  5.         int widthSize = MeasureSpec.getSize(widthMeasureSpec);  
  6.         int heightSize = MeasureSpec.getSize(heightMeasureSpec);  
  7.   
  8.         int width = calculateLayoutWidth(widthSize, widthMode);  
  9.   
  10.         int height;  
  11.         if (heightMode == MeasureSpec.EXACTLY) {  
  12.             height = heightSize;  
  13.         } else {  
  14.             height = getDesiredHeight(itemsLayout);  
  15.   
  16.             if (heightMode == MeasureSpec.AT_MOST) {  
  17.                 height = Math.min(height, heightSize);  
  18.             }  
  19.         }  
  20.   
  21.         setMeasuredDimension(width, height);  
  22.     }  

里面用到了532行calculateLayoutWidth()的方法,就是计算Layout的宽度,在calculateLayoutWidth()这个方法里面调用了

[java]  view plain copy
  1. /** 
  2.      * Creates layouts 
  3.      * @param widthItems width of items layout 
  4.      * @param widthLabel width of label layout 
  5.      */  
  6.     private void createLayouts(int widthItems, int widthLabel) {  
  7.         if (itemsLayout == null || itemsLayout.getWidth() > widthItems) {  
  8.             itemsLayout = new StaticLayout(buildText(isScrollingPerformed), itemsPaint, widthItems,  
  9.                     widthLabel > 0 ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER,  
  10.                     1, ADDITIONAL_ITEM_HEIGHT, false);  
  11.         } else {  
  12.             itemsLayout.increaseWidthTo(widthItems);  
  13.         }  
  14.   
  15.         if (!isScrollingPerformed && (valueLayout == null || valueLayout.getWidth() > widthItems)) {  
  16.             String text = getAdapter() != null ? getAdapter().getItem(currentItem) : null;  
  17.             valueLayout = new StaticLayout(text != null ? text : "",  
  18.                     valuePaint, widthItems, widthLabel > 0 ?  
  19.                             Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER,  
  20.                             1, ADDITIONAL_ITEM_HEIGHT, false);  
  21.         } else if (isScrollingPerformed) {  
  22.             valueLayout = null;  
  23.         } else {  
  24.             valueLayout.increaseWidthTo(widthItems);  
  25.         }  
  26.   
  27.         if (widthLabel > 0) {  
  28.             if (labelLayout == null || labelLayout.getWidth() > widthLabel) {  
  29.                 labelLayout = new StaticLayout(label, valuePaint,  
  30.                         widthLabel, Layout.Alignment.ALIGN_NORMAL, 1,  
  31.                         ADDITIONAL_ITEM_HEIGHT, false);  
  32.             } else {  
  33.                 labelLayout.increaseWidthTo(widthLabel);  
  34.             }  
  35.         }  
  36.     }  

然后我们接着看onDraw()方法:

[java]  view plain copy
  1. @Override  
  2.     protected void onDraw(Canvas canvas) {  
  3.         super.onDraw(canvas);  
  4.           
  5.         if (itemsLayout == null) {  
  6.             if (itemsWidth == 0) {  
  7.                 calculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY);  
  8.             } else {  
  9.                 createLayouts(itemsWidth, labelWidth);  
  10.             }  
  11.         }  
  12.   
  13.         if (itemsWidth > 0) {  
  14.             canvas.save();  
  15.             // Skip padding space and hide a part of top and bottom items  
  16.             canvas.translate(PADDING, -ITEM_OFFSET);  
  17.             drawItems(canvas);  
  18.             drawValue(canvas);  
  19.             canvas.restore();  
  20.         }  
  21.   
  22.         drawCenterRect(canvas);  
  23.         drawShadows(canvas);  
  24.     }  

在onDraw方法中,也调用了CreateLayout()方法,然后在后面调用drawCenterRect()、drawItems()、drawValue()、绘制阴影drawShadows()两个方法:

[java]  view plain copy
  1. /** 
  2.      * Draws shadows on top and bottom of control 
  3.      * @param canvas the canvas for drawing 
  4.      */  
  5.     private void drawShadows(Canvas canvas) {  
  6.         topShadow.setBounds(00, getWidth(), getHeight() / visibleItems);  
  7.         topShadow.draw(canvas);  
  8.   
  9.   
  10.         bottomShadow.setBounds(0, getHeight() - getHeight() / visibleItems,  
  11.                 getWidth(), getHeight());  
  12.         bottomShadow.draw(canvas);  
  13.     }  
  14.   
  15.   
  16.     /** 
  17.      * Draws value and label layout 
  18.      * @param canvas the canvas for drawing 
  19.      */  
  20.     private void drawValue(Canvas canvas) {  
  21.         valuePaint.setColor(VALUE_TEXT_COLOR);  
  22.         valuePaint.drawableState = getDrawableState();  
  23.   
  24.   
  25.         Rect bounds = new Rect();  
  26.         itemsLayout.getLineBounds(visibleItems / 2, bounds);  
  27.   
  28.   
  29.         // draw label  
  30.         if (labelLayout != null) {  
  31.             canvas.save();  
  32.             canvas.translate(itemsLayout.getWidth() + LABEL_OFFSET, bounds.top);  
  33.             labelLayout.draw(canvas);  
  34.             canvas.restore();  
  35.         }  
  36.   
  37.   
  38.         // draw current value  
  39.         if (valueLayout != null) {  
  40.             canvas.save();  
  41.             canvas.translate(0, bounds.top + scrollingOffset);  
  42.             valueLayout.draw(canvas);  
  43.             canvas.restore();  
  44.         }  
  45.     }  
  46.   
  47.   
  48.     /** 
  49.      * Draws items 
  50.      * @param canvas the canvas for drawing 
  51.      */  
  52.     private void drawItems(Canvas canvas) {  
  53.         canvas.save();  
  54.           
  55.         int top = itemsLayout.getLineTop(1);  
  56.         canvas.translate(0, - top + scrollingOffset);  
  57.           
  58.         itemsPaint.setColor(ITEMS_TEXT_COLOR);  
  59.         itemsPaint.drawableState = getDrawableState();  
  60.         itemsLayout.draw(canvas);  
  61.           
  62.         canvas.restore();  
  63.     }  
  64.   
  65.   
  66.     /** 
  67.      * Draws rect for current value 
  68.      * @param canvas the canvas for drawing 
  69.      */  
  70.     private void drawCenterRect(Canvas canvas) {  
  71.         int center = getHeight() / 2;  
  72.         int offset = getItemHeight() / 2;  
  73.         centerDrawable.setBounds(0, center - offset, getWidth(), center + offset);  
  74.         centerDrawable.draw(canvas);  
  75.     }  


主要就是通过canvas类进行图形的绘制。


       最后,我们看下840行定义的手势监听:

[java]  view plain copy
  1. // gesture listener  
  2.     private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {  
  3.         public boolean onDown(MotionEvent e) {  
  4.             if (isScrollingPerformed) {  
  5.                 scroller.forceFinished(true);  
  6.                 clearMessages();  
  7.                 return true;  
  8.             }  
  9.             return false;  
  10.         }  
  11.           
  12.         public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {  
  13.             startScrolling();  
  14.             doScroll((int)-distanceY);  
  15.             return true;  
  16.         }  
  17.           
  18.         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {  
  19.             lastScrollY = currentItem * getItemHeight() + scrollingOffset;  
  20.             int maxY = isCyclic ? 0x7FFFFFFF : adapter.getItemsCount() * getItemHeight();  
  21.             int minY = isCyclic ? -maxY : 0;  
  22.             scroller.fling(0, lastScrollY, 0, (int) -velocityY / 200, minY, maxY);  
  23.             setNextMessage(MESSAGE_SCROLL);  
  24.             return true;  
  25.         }  
  26.     };  

        里面主要调用的方法:clearMessages()、startScrolling()、doScroll()、setNextMessage(),先看下中间的两个方法开始滑动和滑动

[java]  view plain copy
  1. /** 
  2.      * Scrolls the wheel 
  3.      * @param delta the scrolling value 
  4.      */  
  5.     private void doScroll(int delta) {  
  6.         scrollingOffset += delta;         
  7.         int count = scrollingOffset / getItemHeight();  
  8.         int pos = currentItem - count;  
  9.         if (isCyclic && adapter.getItemsCount() > 0) {  
  10.             // fix position by rotating  
  11.             while (pos < 0) {  
  12.                 pos += adapter.getItemsCount();  
  13.             }  
  14.             pos %= adapter.getItemsCount();  
  15.         } else if (isScrollingPerformed) {  
  16.             //   
  17.             if (pos < 0) {  
  18.                 count = currentItem;  
  19.                 pos = 0;  
  20.             } else if (pos >= adapter.getItemsCount()) {  
  21.                 count = currentItem - adapter.getItemsCount() + 1;  
  22.                 pos = adapter.getItemsCount() - 1;  
  23.             }  
  24.         } else {  
  25.             // fix position  
  26.             pos = Math.max(pos, 0);  
  27.             pos = Math.min(pos, adapter.getItemsCount() - 1);  
  28.         }  
  29.           
  30.         int offset = scrollingOffset;  
  31.         if (pos != currentItem) {  
  32.             setCurrentItem(pos, false);  
  33.         } else {  
  34.             invalidate();  
  35.         }  
  36.           
  37.         // update offset  
  38.         scrollingOffset = offset - count * getItemHeight();  
  39.         if (scrollingOffset > getHeight()) {  
  40.             scrollingOffset = scrollingOffset % getHeight() + getHeight();  
  41.         }  
  42.     }  

[java]  view plain copy
  1. /** 
  2.      * Starts scrolling 
  3.      */  
  4.     private void startScrolling() {  
  5.         if (!isScrollingPerformed) {  
  6.             isScrollingPerformed = true;  
  7.             notifyScrollingListenersAboutStart();  
  8.         }  
  9.     }  

在startScrolling方法里面有287行的notifyScrollingListenersAboutStart函数。

再看clearMessages()、setMessageNext()

[java]  view plain copy
  1. private void setNextMessage(int message) {  
  2.         clearMessages();  
  3.         animationHandler.sendEmptyMessage(message);  
  4.     }  
  5.   
  6.   
  7.     /** 
  8.      * Clears messages from queue 
  9.      */  
  10.     private void clearMessages() {  
  11.         animationHandler.removeMessages(MESSAGE_SCROLL);  
  12.         animationHandler.removeMessages(MESSAGE_JUSTIFY);  
  13.     }  

里面使用到了animationHandler,用来传递动画有段的操作:

[java]  view plain copy
  1. // animation handler  
  2.     private Handler animationHandler = new Handler() {  
  3.         public void handleMessage(Message msg) {  
  4.             scroller.computeScrollOffset();  
  5.             int currY = scroller.getCurrY();  
  6.             int delta = lastScrollY - currY;  
  7.             lastScrollY = currY;  
  8.             if (delta != 0) {  
  9.                 doScroll(delta);  
  10.             }  
  11.               
  12.             // scrolling is not finished when it comes to final Y  
  13.             // so, finish it manually   
  14.             if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {  
  15.                 currY = scroller.getFinalY();  
  16.                 scroller.forceFinished(true);  
  17.             }  
  18.             if (!scroller.isFinished()) {  
  19.                 animationHandler.sendEmptyMessage(msg.what);  
  20.             } else if (msg.what == MESSAGE_SCROLL) {  
  21.                 justify();  
  22.             } else {  
  23.                 finishScrolling();  
  24.             }  
  25.         }  
  26.     };  

里面调用了finishScrolling()

[java]  view plain copy
  1. /** 
  2.      * Finishes scrolling 
  3.      */  
  4.     void finishScrolling() {  
  5.         if (isScrollingPerformed) {  
  6.             notifyScrollingListenersAboutEnd();  
  7.             isScrollingPerformed = false;  
  8.         }  
  9.         invalidateLayouts();  
  10.         invalidate();  
  11.     }  

                                                                                            

http://blog.csdn.net/lilu_leo/article/details/7399015

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值