Android custom implement loop scroll wheel control WheelView

Source: Internet
Author: User
Tags drawtext

Android custom implement loop scroll wheel control WheelView

First, submit

Now the wheel layout is used in many places. For example, when choosing a birthday, the style is similar to the DatePickerDialog provided by the system, and there are many open-source controls, however, most of the interfaces are drawn based on the current project requirements, so I wrote a WheelView that suits my project.

First, this control has the following requirements:

1. It can scroll cyclically. When sliding up or down to the critical value, the loop starts to scroll.

2. There is a semi-transparent selection area in the middle. When the sliding ends, you can choose which one is in this selection area.

3. Draw from View

Then we will explain some key points:

1. The overall control inherits from the View and is drawn in onDraw. It consists of three modules: the entire View, each entry, and the entries in the intermediate selection area (an additional gray area is drawn ).

2. Add a display entry number at the top and bottom of each entry through dynamic setting or default setting, that is, draw showCount + 2 entries in total.

3. When the number of top items slide more than half of the height of the entries, update the dynamic entries: delete the bottom entry to add the first entry, and delete the first entry to the bottom entry.

4. You can set the number of entries displayed, font size, color, text displayed in the selection area (the year in the figure), default options, and padding whitelist.

5. In onTouchEvent, get the gradient value of finger sliding and dynamically update all the current entries.

6. dynamically calculate the width, width, height, and Y coordinate of all entries in onMeasure.

7. If more than half of the coordinates of the current entry and the selected entry are selected, it is regarded as selected and slide to the corresponding position.

The following is the WheelView code, mainly used to calculate the initial value and obtain the value set outside:

Package cc. wxf. view. wheel; import android. content. context; import android. graphics. canvas; import android. graphics. color; import android. graphics. paint; import android. util. attributeSet; import android. view. motionEvent; import android. view. view; import java. util. arrayList; import java. util. list;/*** Created by ccwxf on 2016/3/31. */public class WheelView extends View {public static final int FONT_COLOR = Color. BLACK; public static final int FONT_SIZE = 30; public static final int PADDING = 10; public static final int SHOW_COUNT = 3; public static final int SELECT = 0; // private int width; private int height; private int itemHeight; // number of rows to be displayed private int showCount = SHOW_COUNT; // The default position private int select = SELECT; // font color, size, and padding private int fontColor = FONT_COLOR; private int fontSize = FONT_SIZE; private int PADDING = padding; // text List private List
 
  
Lists; // The secondary Text of the selected Item, which can be empty private String selectTip; // each Item and the selected Item private List
  
   
WheelItems = new ArrayList
   
    
(); Private WheelSelect wheelSelect = null; // Y coordinate of hand-clicked private float mTouchY; // listener private OnWheelViewItemSelectListener; public WheelView (Context context) {super (context );} public WheelView (Context context, AttributeSet attrs) {super (context, attrs);} public WheelView (Context context, AttributeSet attrs, int defStyleAttr) {super (context, attrs, defStyleAttr);}/*** set the font color. If not set, the default value is black * @ param fontColor * @ return */public WheelView fontColor (int fontColor) {this. fontColor = fontColor; return this;}/*** set the font size. If not set, the default value is 30 * @ param fontSize * @ return */public WheelView fontSize (int fontSize) {this. fontSize = fontSize; return this;}/*** sets the text to the padding between the upper and lower sides, the default value is 10 * @ param padding * @ return */public WheelView padding (int padding) {this. padding = padding; return this;}/*** sets the copy text of the selected item. You can leave * @ param selectTip * @ return */public WheelView selectTip (String selectTip) unspecified) {this. selectTip = selectTip; return this;}/*** set the text List. The * @ param lists * @ return */public WheelView lists (List
    
     
Lists) {this. lists = lists; return this;}/*** sets the number of lines to be displayed. If this parameter is not set, the default value is 3 * @ param showCount * @ return */public WheelView showCount (int showCount) {if (showCount % 2 = 0) {throw new IllegalStateException ("the showCount must be odd");} this. showCount = showCount; return this;}/*** sets the index of the selected text by default, if this parameter is not set, the default value is 0 * @ param select * @ return */public WheelView select (int select) {this. select = select; return this ;} /*** The last called method to determine whether the function is necessary. * @ return */public WheelView build () {if (lists = null) {throw new IllegalStateException ("this method must invoke after the method [lists]");} return this ;}@ Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {// obtain the overall width = MeasureSpec. getSize (widthMeasureSpec)-getPaddingLeft ()-getPaddingRight (); // get the height of each Item. Paint mPaint = ne W Paint (); mPaint. setTextSize (fontSize); Paint. fontMetrics metrics = mPaint. getFontMetrics (); itemHeight = (int) (metrics. bottom-metrics. top) + 2 * padding; // initialize every WheelItem initWheelItems (width, itemHeight); // initialize WheelSelect wheelSelect = new WheelSelect (showCount/2 * itemHeight, width, itemHeight, selectTip, fontColor, fontSize, padding); // obtain all the heights: height = itemHeight * showCount; super. onM Easure (widthMeasureSpec, MeasureSpec. makeMeasureSpec (height, MeasureSpec. EXACTLY);}/*** create display count + 2 wheelItems * @ param width * @ param itemHeight */private void initWheelItems (int width, int itemHeight) {wheelItems. clear (); for (int I = 0; I <showCount + 2; I ++) {int startY = itemHeight * (I-1 ); int stringIndex = select-showCount/2-1 + I; if (stringIndex <0) {stringIndex = lists. size () + StringIndex;} wheelItems. add (new WheelItem (startY, width, itemHeight, fontColor, fontSize, lists. get (stringIndex); }}@ Override public boolean onTouchEvent (MotionEvent event) {switch (event. getAction () {case MotionEvent. ACTION_DOWN: mTouchY = event. getY (); return true; case MotionEvent. ACTION_MOVE: float dy = event. getY ()-mTouchY; mTouchY = event. getY (); handleMove (dy); break; case Motion Event. ACTION_UP: handleUp (); break;} return super. onTouchEvent (event);}/*** process mobile operations * @ param dy */private void handleMove (float dy) {// Adjust coordinates for (WheelItem item: wheelItems) {item. adjust (dy);} invalidate (); // adjust ();}/*** handle lift operation */private void handleUp () {int index =-1; // obtain the selected for (int I = 0; I <wheelItems. size (); I ++) {WheelItem item = wheelItems. get (I); // If startY is in selectItem If (item. getStartY ()> wheelSelect. getStartY () & item. getStartY () <(wheelSelect. getStartY () + itemHeight/2) {index = I; break;} // if startY is under the selectItem midpoint, the previous item is used as the selection item if (item. getStartY ()> = (wheelSelect. getStartY () + itemHeight/2) & item. getStartY () <(wheelSelect. getStartY () + itemHeight) {index = I-1; break ;}}// if no or other factors are found, if (index =-1) is returned directly) {return;} // get the offset fl Oat dy = wheelSelect. getStartY ()-wheelItems. get (index ). getStartY (); // Adjust coordinates for (WheelItem item: wheelItems) {item. adjust (dy);} invalidate (); // adjust (); // set the selection item int stringIndex = lists. indexOf (wheelItems. get (index ). getText (); if (stringIndex! =-1) {select = stringIndex; if (listener! = Null) {listener. onItemSelect (select) ;}}/ *** adjust Item movement and cycle display */private void adjust () {// If sliding down beyond the height of half an Item, then adjust the container if (wheelItems. get (0 ). getStartY ()> =-itemHeight/2) {// remove the last Item and reuse WheelItem item = wheelItems. remove (wheelItems. size ()-1); // sets the Y coordinate item of the starting point. setStartY (wheelItems. get (0 ). getStartY ()-itemHeight); // get the text index int index = lists in the container. indexOf (wheelItems. get (0 ). getText (); if (index =-1) {Return;} index-= 1; if (index <0) {index = lists. size () + index;} // sets the text item. setText (lists. get (index); // Add it to the start of the wheelItems. add (0, item); invalidate (); return;} // adjust the container if (wheelItems. get (0 ). getStartY () <= (-itemHeight/2-itemHeight) {// remove the first Item and reuse WheelItem item = wheelItems. remove (0); // sets the Y coordinate item of the starting point. setStartY (wheelItems. get (wheelItems. size ()-1 ). getStartY () + itemHei Ght); // obtain the text index int index = lists in the container. indexOf (wheelItems. get (wheelItems. size ()-1 ). getText (); if (index =-1) {return;} index + = 1; if (index> = lists. size () {index = 0;} // sets the text item. setText (lists. get (index); // Add it to the end of the wheelItems. add (item); invalidate (); return ;}/ *** get the current selection item */public int getSelectItem () {return select ;} @ Override protected void onDraw (Canvas canvas) {// draw each Item for (W HeelItem item: wheelItems) {item. onDraw (canvas) ;}// draw the shadow if (wheelSelect! = Null) {wheelSelect. onDraw (canvas) ;}}/*** set listener * @ param listener * @ return */public WheelView listener (OnWheelViewItemSelectListener listener) {this. listener = listener; return this;} public interface OnWheelViewItemSelectListener {void onItemSelect (int index );}}
    
   
  
 
Next is each entry class, which is drawn based on the current coordinate and changed based on the gradient value:
Package cc. wxf. view. wheel; import android. graphics. canvas; import android. graphics. paint; import android. graphics. rectF;/*** Created by ccwxf on 2016/3/31. */public class WheelItem {// start point Y coordinate, width, and height private float startY; private int width; private int height; // four-point coordinate private RectF rect = new RectF (); // font size and color: private int fontColor; private int fontSize; private String text; private Paint mPaint = new Paint (Paint. ANTI_ALIAS_FLAG); public WheelItem (float startY, int width, int height, int fontColor, int fontSize, String text) {this. startY = startY; this. width = width; this. height = height; this. fontColor = fontColor; this. fontSize = fontSize; this. text = text; adjust (0);}/*** adjust the four-point coordinate value * @ param dy */public void adjust (float dy) based on the Y coordinate value) {startY + = dy; rect. left = 0; rect. top = startY; rect. right = width; rect. bottom = startY + height;} public float getStartY () {return startY;}/*** directly sets the Y coordinate attribute, adjust the four-point coordinate attribute * @ param startY */public void setStartY (float startY) {this. startY = startY; rect. left = 0; rect. top = startY; rect. right = width; rect. bottom = startY + height;} public void setText (String text) {this. text = text;} public String getText () {return text;} public void onDraw (Canvas mCanvas) {// set the pen attribute mPaint. setTextSize (fontSize); mPaint. setColor (fontColor); // get the font width int textWidth = (int) mPaint. measureText (text); // the starting point of drawText is the lower left corner, and the starting point of the Y axis is baseLine Paint. fontMetrics metrics = mPaint. getFontMetrics (); int baseLine = (int) (rect. centerY () + (metrics. bottom-metrics. top)/2-metrics. bottom); // center the mCanvas. drawText (text, rect. centerX ()-textWidth/2, baseLine, mPaint );}}

Finally, you have to draw a gray area in the middle area:
Package cc. wxf. view. wheel; import android. graphics. canvas; import android. graphics. color; import android. graphics. paint; import android. graphics. rect;/*** Created by ccwxf on 2016/4/1. */public class WheelSelect {// black box background Color public static final int COLOR_BACKGROUND = Color. parseColor ("#77777777"); // start point, width, and height of the Y coordinate of the Black Box private int startY; private int width; private int height; // four-point coordinate private Rect rect = new Rect (); // select the color and size of the text, and fill in the private String selectText; private int fontColor; private int fontSize; private int padding; private Paint mPaint = new Paint (Paint. ANTI_ALIAS_FLAG); public WheelSelect (int startY, int width, int height, String selectText, int fontColor, int fontSize, int padding) {this. startY = startY; this. width = width; this. height = height; this. selectText = selectText; this. fontColo R = fontColor; this. fontSize = fontSize; this. padding = padding; rect. left = 0; rect. top = startY; rect. right = width; rect. bottom = startY + height;} public int getStartY () {return startY;} public void setStartY (int startY) {this. startY = startY;} public void onDraw (Canvas mCanvas) {// draw the background mPaint. setStyle (Paint. style. FILL); mPaint. setColor (COLOR_BACKGROUND); mCanvas. drawRect (rect, mPaint ); // Draw the reminder text if (selectText! = Null) {// set the pen attribute mPaint. setTextSize (fontSize); mPaint. setColor (fontColor); // get the font width int textWidth = (int) mPaint. measureText (selectText); // the starting point of drawText is the lower left corner, and the starting point of the Y axis is baseLine Paint. fontMetrics metrics = mPaint. getFontMetrics (); int baseLine = (int) (rect. centerY () + (metrics. bottom-metrics. top)/2-metrics. bottom); // draw the text mCanvas on the right. drawText (selectText, rect. right-padding-textWidth, baseLine, mPaint );}}}


The source code contains three files, which are simple and detailed, and the following is the file:

 

 

Final WheelView wheelView = (WheelView) findViewById (R. id. wheelView); final List
 
  
Lists = new ArrayList <> (); for (int I = 0; I <20; I ++) {lists. add ("test:" + I);} wheelView. lists (lists ). fontSize (35 ). showCount (5 ). selectTip ("year "). select (0 ). listener (new WheelView. onWheelViewItemSelectListener () {@ Override public void onItemSelect (int index) {Log. d ("cc", "current select:" + wheelView. getSelectItem () + "index:" + index + ", result =" + lists. get (index ));}}). build ();
 

This control is simple and complex. The most basic onDraw implementation allows you to flexibly customize your own needs.

The demo project is not provided and is easy to use.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.