Welcome 微信登录

首页 / 操作系统 / Linux / Android-仿iPhone滚轮控件效果

在坛子里看到的,自己弄个Android-仿iPhone滚轮控件效果:
这个滚动的WheelView
  1. /* 
  2.  *  Android Wheel Control. 
  3.  *  https://code.google.com/p/android-wheel/ 
  4.  *   
  5.  *  Copyright 2010 Yuri Kanivets 
  6.  * 
  7.  *  Licensed under the Apache License, Version 2.0 (the "License"); 
  8.  *  you may not use this file except in compliance with the License. 
  9.  *  You may obtain a copy of the License at 
  10.  * 
  11.  *  http://www.apache.org/licenses/LICENSE-2.0 
  12.  * 
  13.  *  Unless required by applicable law or agreed to in writing, software 
  14.  *  distributed under the License is distributed on an "AS IS" BASIS, 
  15.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  16.  *  See the License for the specific language governing permissions and 
  17.  *  limitations under the License. 
  18.  */  
  19.   
  20. package kankan.wheel.widget;  
  21.   
  22. import java.util.LinkedList;  
  23. import java.util.List;  
  24.   
  25. import android.content.Context;  
  26. import android.graphics.Canvas;  
  27. import android.graphics.Paint;  
  28. import android.graphics.Rect;  
  29. import android.graphics.drawable.Drawable;  
  30. import android.graphics.drawable.GradientDrawable;  
  31. import android.graphics.drawable.GradientDrawable.Orientation;  
  32. import android.os.Handler;  
  33. import android.os.Message;  
  34. import android.text.Layout;  
  35. import android.text.StaticLayout;  
  36. import android.text.TextPaint;  
  37. import android.util.AttributeSet;  
  38. import android.util.FloatMath;  
  39. import android.view.GestureDetector;  
  40. import android.view.GestureDetector.SimpleOnGestureListener;  
  41. import android.view.MotionEvent;  
  42. import android.view.View;  
  43. import android.view.animation.Interpolator;  
  44. import android.widget.Scroller;  
  45.   
  46. import com.shao.pwd.R;  
  47.   
  48. /** 
  49.  * Numeric wheel view. 
  50.  *  
  51.  * @author Yuri Kanivets 
  52.  */  
  53. public class WheelView extends View {  
  54.     /** Scrolling duration */  
  55.     private static final int SCROLLING_DURATION = 400;  
  56.   
  57.     /** Minimum delta for scrolling */  
  58.     private static final int MIN_DELTA_FOR_SCROLLING = 1;  
  59.   
  60.     /** Current value & label text color */  
  61.     private static final int VALUE_TEXT_COLOR = 0xF0000000;  
  62.   
  63.     /** Items text color */  
  64.     private static final int ITEMS_TEXT_COLOR = 0xFF000000;  
  65.   
  66.     /** Top and bottom shadows colors */  
  67.     private static final int[] SHADOWS_COLORS = new int[] { 0xFF111111,  
  68.             0x00AAAAAA0x00AAAAAA };  
  69.   
  70.     /** Additional items height (is added to standard text item height) */  
  71.     private static final int ADDITIONAL_ITEM_HEIGHT = 15;  
  72.   
  73.     /** Text size */  
  74.     private static final int TEXT_SIZE = 24;  
  75.   
  76.     /** Top and bottom items offset (to hide that) */  
  77.     private static final int ITEM_OFFSET = TEXT_SIZE / 5;  
  78.   
  79.     /** Additional width for items layout */  
  80.     private static final int ADDITIONAL_ITEMS_SPACE = 10;  
  81.   
  82.     /** Label offset */  
  83.     private static final int LABEL_OFFSET = 8;  
  84.   
  85.     /** Left and right padding value */  
  86.     private static final int PADDING = 10;  
  87.   
  88.     /** Default count of visible items */  
  89.     private static final int DEF_VISIBLE_ITEMS = 5;  
  90.   
  91.     // Wheel Values   
  92.     private WheelAdapter adapter = null;  
  93.     private int currentItem = 0;  
  94.       
  95.     // Widths   
  96.     private int itemsWidth = 0;  
  97.     private int labelWidth = 0;  
  98.   
  99.     // Count of visible items   
  100.     private int visibleItems = DEF_VISIBLE_ITEMS;  
  101.       
  102.     // Item height   
  103.     private int itemHeight = 0;  
  104.   
  105.     // Text paints   
  106.     private TextPaint itemsPaint;  
  107.     private TextPaint valuePaint;  
  108.   
  109.     // Layouts   
  110.     private StaticLayout itemsLayout;  
  111.     private StaticLayout labelLayout;  
  112.     private StaticLayout valueLayout;  
  113.   
  114.     // Label & background   
  115.     private String label;  
  116.     private Drawable centerDrawable;  
  117.   
  118.     // Shadows drawables   
  119.     private GradientDrawable topShadow;  
  120.     private GradientDrawable bottomShadow;  
  121.   
  122.     // Scrolling   
  123.     private boolean isScrollingPerformed;   
  124.     private int scrollingOffset;  
  125.   
  126.     // Scrolling animation   
  127.     private GestureDetector gestureDetector;  
  128.     private Scroller scroller;  
  129.     private int lastScrollY;  
  130.   
  131.     // Cyclic   
  132.     boolean isCyclic = false;  
  133.       
  134.     // Listeners   
  135.     private List<OnWheelChangedListener> changingListeners = new LinkedList<OnWheelChangedListener>();  
  136.     private List<OnWheelScrollListener> scrollingListeners = new LinkedList<OnWheelScrollListener>();  
  137.   
  138.     /** 
  139.      * Constructor 
  140.      */  
  141.     public WheelView(Context context, AttributeSet attrs, int defStyle) {  
  142.         super(context, attrs, defStyle);  
  143.         initData(context);  
  144.     }  
  145.   
  146.     /** 
  147.      * Constructor 
  148.      */  
  149.     public WheelView(Context context, AttributeSet attrs) {  
  150.         super(context, attrs);  
  151.         initData(context);  
  152.     }  
  153.   
  154.     /** 
  155.      * Constructor 
  156.      */  
  157.     public WheelView(Context context) {  
  158.         super(context);  
  159.         initData(context);  
  160.     }  
  161.       
  162.     /** 
  163.      * Initializes class data 
  164.      * @param context the context 
  165.      */  
  166.     private void initData(Context context) {  
  167.         gestureDetector = new GestureDetector(context, gestureListener);  
  168.         gestureDetector.setIsLongpressEnabled(false);  
  169.           
  170.         scroller = new Scroller(context);  
  171.     }  
  172.       
  173.     /** 
  174.      * Gets wheel adapter 
  175.      * @return the adapter 
  176.      */  
  177.     public WheelAdapter getAdapter() {  
  178.         return adapter;  
  179.     }  
  180.       
  181.     /** 
  182.      * Sets wheel adapter 
  183.      * @param adapter the new wheel adapter 
  184.      */  
  185.     public void setAdapter(WheelAdapter adapter) {  
  186.         this.adapter = adapter;  
  187.         invalidateLayouts();  
  188.         invalidate();  
  189.     }  
  190.       
  191.     /** 
  192.      * Set the the specified scrolling interpolator 
  193.      * @param interpolator the interpolator 
  194.      */  
  195.     public void setInterpolator(Interpolator interpolator) {  
  196.         scroller.forceFinished(true);  
  197.         scroller = new Scroller(getContext(), interpolator);  
  198.     }  
  199.       
  200.     /** 
  201.      * Gets count of visible items 
  202.      *  
  203.      * @return the count of visible items 
  204.      */  
  205.     public int getVisibleItems() {  
  206.         return visibleItems;  
  207.     }  
  208.   
  209.     /** 
  210.      * Sets count of visible items 
  211.      *  
  212.      * @param count 
  213.      *            the new count 
  214.      */  
  215.     public void setVisibleItems(int count) {  
  216.         visibleItems = count;  
  217.         invalidate();  
  218.     }  
  219.   
  220.     /** 
  221.      * Gets label 
  222.      *  
  223.      * @return the label 
  224.      */  
  225.     public String getLabel() {  
  226.         return label;  
  227.     }  
  228.   
  229.     /** 
  230.      * Sets label 
  231.      *  
  232.      * @param newLabel 
  233.      *            the label to set 
  234.      */  
  235.     public void setLabel(String newLabel) {  
  236.         if (label == null || !label.equals(newLabel)) {  
  237.             label = newLabel;  
  238.             labelLayout = null;  
  239.             invalidate();  
  240.         }  
  241.     }  
  242.       
  243.     /** 
  244.      * Adds wheel changing listener 
  245.      * @param listener the listener  
  246.      */  
  247.     public void addChangingListener(OnWheelChangedListener listener) {  
  248.         changingListeners.add(listener);  
  249.     }  
  250.   
  251.     /** 
  252.      * Removes wheel changing listener 
  253.      * @param listener the listener 
  254.      */  
  255.     public void removeChangingListener(OnWheelChangedListener listener) {  
  256.         changingListeners.remove(listener);  
  257.     }  
  258.       
  259.     /** 
  260.      * Notifies changing listeners 
  261.      * @param oldValue the old wheel value 
  262.      * @param newValue the new wheel value 
  263.      */  
  264.     protected void notifyChangingListeners(int oldValue, int newValue) {  
  265.         for (OnWheelChangedListener listener : changingListeners) {  
  266.             listener.onChanged(this, oldValue, newValue);  
  267.         }  
  268.     }  
  269.   
  270.     /** 
  271.      * Adds wheel scrolling listener 
  272.      * @param listener the listener  
  273.      */  
  274.     public void addScrollingListener(OnWheelScrollListener listener) {  
  275.         scrollingListeners.add(listener);  
  276.     }  
  277.   
  278.     /** 
  279.      * Removes wheel scrolling listener 
  280.      * @param listener the listener 
  281.      */  
  282.     public void removeScrollingListener(OnWheelScrollListener listener) {  
  283.         scrollingListeners.remove(listener);  
  284.     }  
  285.       
  286.     /** 
  287.      * Notifies listeners about starting scrolling 
  288.      */  
  289.     protected void notifyScrollingListenersAboutStart() {  
  290.         for (OnWheelScrollListener listener : scrollingListeners) {  
  291.             listener.onScrollingStarted(this);  
  292.         }  
  293.     }  
  294.   
  295.     /** 
  296.      * Notifies listeners about ending scrolling 
  297.      */  
  298.     protected void notifyScrollingListenersAboutEnd() {  
  299.         for (OnWheelScrollListener listener : scrollingListeners) {  
  300.             listener.onScrollingFinished(this);  
  301.         }  
  302.     }  
  303.   
  304.     /** 
  305.      * Gets current value 
  306.      *  
  307.      * @return the current value 
  308.      */  
  309.     public int getCurrentItem() {  
  310.         return currentItem;  
  311.     }  
  312.   
  313.     /** 
  314.      * Sets the current item. Does nothing when index is wrong. 
  315.      *  
  316.      * @param index the item index 
  317.      * @param animated the animation flag 
  318.      */  
  319.     public void setCurrentItem(int index, boolean animated) {  
  320.         if (adapter == null || adapter.getItemsCount() == 0) {  
  321.             return// throw?   
  322.         }  
  323.         if (index < 0 || index >= adapter.getItemsCount()) {  
  324.             if (isCyclic) {  
  325.                 while (index < 0) {  
  326.                     index += adapter.getItemsCount();  
  327.                 }  
  328.                 index %= adapter.getItemsCount();  
  329.             } else{  
  330.                 return// throw?   
  331.             }  
  332.         }  
  333.         if (index != currentItem) {  
  334.             if (animated) {  
  335.                 scroll(index - currentItem, SCROLLING_DURATION);  
  336.             } else {  
  337.                 invalidateLayouts();  
  338.               
  339.                 int old = currentItem;  
  340.                 currentItem = index;  
  341.               
  342.                 notifyChangingListeners(old, currentItem);  
  343.               
  344.                 invalidate();  
  345.             }  
  346.         }  
  347.     }  
  348.   
  349.     /** 
  350.      * Sets the current item w/o animation. Does nothing when index is wrong. 
  351.      *  
  352.      * @param index the item index 
  353.      */  
  354.     public void setCurrentItem(int index) {  
  355.         setCurrentItem(index, false);  
  356.     }     
  357.       
  358.     /** 
  359.      * Tests if wheel is cyclic. That means before the 1st item there is shown the last one 
  360.      * @return true if wheel is cyclic 
  361.      */  
  362.     public boolean isCyclic() {  
  363.         return isCyclic;  
  364.     }  
  365.   
  366.     /** 
  367.      * Set wheel cyclic flag 
  368.      * @param isCyclic the flag to set 
  369.      */  
  370.     public void setCyclic(boolean isCyclic) {  
  371.         this.isCyclic = isCyclic;  
  372.           
  373.         invalidate();  
  374.         invalidateLayouts();  
  375.     }  
  376.   
  377.     /** 
  378.      * Invalidates layouts 
  379.      */  
  380.     private void invalidateLayouts() {  
  381.         itemsLayout = null;  
  382.         valueLayout = null;  
  383.         scrollingOffset = 0;  
  384.     }  
  385.   
  386.     /** 
  387.      * Initializes resources 
  388.      */  
  389.     private void initResourcesIfNecessary() {  
  390.         if (itemsPaint == null) {  
  391.             itemsPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG  
  392.                     | Paint.FAKE_BOLD_TEXT_FLAG);  
  393.             //itemsPaint.density = getResources().getDisplayMetrics().density;   
  394.             itemsPaint.setTextSize(TEXT_SIZE);  
  395.         }  
  396.   
  397.         if (valuePaint == null) {  
  398.             valuePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG  
  399.                     | Paint.FAKE_BOLD_TEXT_FLAG | Paint.DITHER_FLAG);  
  400.             //valuePaint.density = getResources().getDisplayMetrics().density;   
  401.             valuePaint.setTextSize(TEXT_SIZE);  
  402.             valuePaint.setShadowLayer(0.1f, 00.1f, 0xFFC0C0C0);  
  403.         }  
  404.   
  405.         if (centerDrawable == null) {  
  406.             centerDrawable = getContext().getResources().getDrawable(R.drawable.wheel_val);  
  407.         }  
  408.   
  409.         if (topShadow == null) {  
  410.             topShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS);  
  411.         }  
  412.   
  413.         if (bottomShadow == null) {  
  414.             bottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS);  
  415.         }  
  416.   
  417.         setBackgroundResource(R.drawable.wheel_bg);  
  418.     }  
  419.   
  420.     /** 
  421.      * Calculates desired height for layout 
  422.      *  
  423.      * @param layout 
  424.      *            the source layout 
  425.      * @return the desired layout height 
  426.      */  
  427.     private int getDesiredHeight(Layout layout) {  
  428.         if (layout == null) {  
  429.             return 0;  
  430.         }  
  431.   
  432.         int desired = getItemHeight() * visibleItems - ITEM_OFFSET * 2  
  433.                 - ADDITIONAL_ITEM_HEIGHT;  
  434.   
  435.         // Check against our minimum height   
  436.         desired = Math.max(desired, getSuggestedMinimumHeight());  
  437.   
  438.         return desired;  
  439.     }  
  440.   
  441.     /** 
  442.      * Returns text item by index 
  443.      * @param index the item index 
  444.      * @return the item or null 
  445.      */  
  446.     private String getTextItem(int index) {  
  447.         if (adapter == null || adapter.getItemsCount() == 0) {  
  448.             return null;  
  449.         }  
  450.         int count = adapter.getItemsCount();  
  451.         if ((index < 0 || index >= count) && !isCyclic) {  
  452.             return null;  
  453.         } else {  
  454.             while (index < 0) {  
  455.                 index = count + index;  
  456.             }  
  457.         }  
  458.           
  459.         index %= count;  
  460.         return adapter.getItem(index);  
  461.     }  
  462.       
  463.     /** 
  464.      * Builds text depending on current value 
  465.      *  
  466.      * @param useCurrentValue 
  467.      * @return the text 
  468.      */  
  469.     private String buildText(boolean useCurrentValue) {  
  470.         StringBuilder itemsText = new StringBuilder();  
  471.         int addItems = visibleItems / 2 + 1;  
  472.   
  473.         for (int i = currentItem - addItems; i <= currentItem + addItems; i++) {  
  474.             if (useCurrentValue || i != currentItem) {  
  475.                 String text = getTextItem(i);  
  476.                 if (text != null) {  
  477.                     itemsText.append(text);  
  478.                 }  
  479.             }  
  480.             if (i < currentItem + addItems) {  
  481.                 itemsText.append(" ");  
  482.             }  
  483.         }  
  484.           
  485.         return itemsText.toString();  
  486.     }  
  487.   
  488.     /** 
  489.      * Returns the max item length that can be present 
  490.      * @return the max length 
  491.      */  
  492.     private int getMaxTextLength() {  
  493.         WheelAdapter adapter = getAdapter();  
  494.         if (adapter == null) {  
  495.             return 0;  
  496.         }  
  497.           
  498.         int adapterLength = adapter.getMaximumLength();  
  499.         if (adapterLength > 0) {  
  500.             return adapterLength;  
  501.         }  
  502.   
  503.         String maxText = null;  
  504.         int addItems = visibleItems / 2;  
  505.         for (int i = Math.max(currentItem - addItems, 0);  
  506.                 i < Math.min(currentItem + visibleItems, adapter.getItemsCount()); i++) {  
  507.             String text = adapter.getItem(i);  
  508.             if (text != null && (maxText == null || maxText.length() < text.length())) {  
  509.                 maxText = text;  
  510.             }  
  511.         }  
  512.   
  513.         return maxText != null ? maxText.length() : 0;  
  514.     }  
  515.   
  516.     /** 
  517.      * Returns height of wheel item 
  518.      * @return the item height 
  519.      */  
  520.     private int getItemHeight() {  
  521.         if (itemHeight != 0) {  
  522.             return itemHeight;  
  523.         } else if (itemsLayout != null && itemsLayout.getLineCount() > 2) {  
  524.             itemHeight = itemsLayout.getLineTop(