Android_开发 实用滚轮效果选择数字(十三)

这个滚动的WheelView

view plain
  1. /*
  2. *AndroidWheelControl.
  3. *https://code.google.com/p/android-wheel/
  4. *
  5. *Copyright2010YuriKanivets
  6. *
  7. *LicensedundertheApacheLicense,Version2.0(the"License");
  8. *youmaynotusethisfileexceptincompliancewiththeLicense.
  9. *YoumayobtainacopyoftheLicenseat
  10. *
  11. *http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  14. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  15. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  16. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  17. *limitationsundertheLicense.
  18. */
  19. packagekankan.wheel.widget;
  20. importjava.util.LinkedList;
  21. importjava.util.List;
  22. importandroid.content.Context;
  23. importandroid.graphics.Canvas;
  24. importandroid.graphics.Paint;
  25. importandroid.graphics.Rect;
  26. importandroid.graphics.drawable.Drawable;
  27. importandroid.graphics.drawable.GradientDrawable;
  28. importandroid.graphics.drawable.GradientDrawable.Orientation;
  29. importandroid.os.Handler;
  30. importandroid.os.Message;
  31. importandroid.text.Layout;
  32. importandroid.text.StaticLayout;
  33. importandroid.text.TextPaint;
  34. importandroid.util.AttributeSet;
  35. importandroid.util.FloatMath;
  36. importandroid.view.GestureDetector;
  37. importandroid.view.GestureDetector.SimpleOnGestureListener;
  38. importandroid.view.MotionEvent;
  39. importandroid.view.View;
  40. importandroid.view.animation.Interpolator;
  41. importandroid.widget.Scroller;
  42. importcom.shao.pwd.R;
  43. /**
  44. *Numericwheelview.
  45. *
  46. *@authorYuriKanivets
  47. */
  48. publicclassWheelViewextendsView{
  49. /**Scrollingduration*/
  50. privatestaticfinalintSCROLLING_DURATION=400;
  51. /**Minimumdeltaforscrolling*/
  52. privatestaticfinalintMIN_DELTA_FOR_SCROLLING=1;
  53. /**Currentvalue&labeltextcolor*/
  54. privatestaticfinalintVALUE_TEXT_COLOR=0xF0000000;
  55. /**Itemstextcolor*/
  56. privatestaticfinalintITEMS_TEXT_COLOR=0xFF000000;
  57. /**Topandbottomshadowscolors*/
  58. privatestaticfinalint[]SHADOWS_COLORS=newint[]{0xFF111111,
  59. 0x00AAAAAA,0x00AAAAAA};
  60. /**Additionalitemsheight(isaddedtostandardtextitemheight)*/
  61. privatestaticfinalintADDITIONAL_ITEM_HEIGHT=15;
  62. /**Textsize*/
  63. privatestaticfinalintTEXT_SIZE=24;
  64. /**Topandbottomitemsoffset(tohidethat)*/
  65. privatestaticfinalintITEM_OFFSET=TEXT_SIZE/5;
  66. /**Additionalwidthforitemslayout*/
  67. privatestaticfinalintADDITIONAL_ITEMS_SPACE=10;
  68. /**Labeloffset*/
  69. privatestaticfinalintLABEL_OFFSET=8;
  70. /**Leftandrightpaddingvalue*/
  71. privatestaticfinalintPADDING=10;
  72. /**Defaultcountofvisibleitems*/
  73. privatestaticfinalintDEF_VISIBLE_ITEMS=5;
  74. //WheelValues
  75. privateWheelAdapteradapter=null;
  76. privateintcurrentItem=0;
  77. //Widths
  78. privateintitemsWidth=0;
  79. privateintlabelWidth=0;
  80. //Countofvisibleitems
  81. privateintvisibleItems=DEF_VISIBLE_ITEMS;
  82. //Itemheight
  83. privateintitemHeight=0;
  84. //Textpaints
  85. privateTextPaintitemsPaint;
  86. privateTextPaintvaluePaint;
  87. //Layouts
  88. privateStaticLayoutitemsLayout;
  89. privateStaticLayoutlabelLayout;
  90. privateStaticLayoutvalueLayout;
  91. //Label&background
  92. privateStringlabel;
  93. privateDrawablecenterDrawable;
  94. //Shadowsdrawables
  95. privateGradientDrawabletopShadow;
  96. privateGradientDrawablebottomShadow;
  97. //Scrolling
  98. privatebooleanisScrollingPerformed;
  99. privateintscrollingOffset;
  100. //Scrollinganimation
  101. privateGestureDetectorgestureDetector;
  102. privateScrollerscroller;
  103. privateintlastScrollY;
  104. //Cyclic
  105. booleanisCyclic=false;
  106. //Listeners
  107. privateList<OnWheelChangedListener>changingListeners=newLinkedList<OnWheelChangedListener>();
  108. privateList<OnWheelScrollListener>scrollingListeners=newLinkedList<OnWheelScrollListener>();
  109. /**
  110. *Constructor
  111. */
  112. publicWheelView(Contextcontext,AttributeSetattrs,intdefStyle){
  113. super(context,attrs,defStyle);
  114. initData(context);
  115. }
  116. /**
  117. *Constructor
  118. */
  119. publicWheelView(Contextcontext,AttributeSetattrs){
  120. super(context,attrs);
  121. initData(context);
  122. }
  123. /**
  124. *Constructor
  125. */
  126. publicWheelView(Contextcontext){
  127. super(context);
  128. initData(context);
  129. }
  130. /**
  131. *Initializesclassdata
  132. *@paramcontextthecontext
  133. */
  134. privatevoidinitData(Contextcontext){
  135. gestureDetector=newGestureDetector(context,gestureListener);
  136. gestureDetector.setIsLongpressEnabled(false);
  137. scroller=newScroller(context);
  138. }
  139. /**
  140. *Getswheeladapter
  141. *@returntheadapter
  142. */
  143. publicWheelAdaptergetAdapter(){
  144. returnadapter;
  145. }
  146. /**
  147. *Setswheeladapter
  148. *@paramadapterthenewwheeladapter
  149. */
  150. publicvoidsetAdapter(WheelAdapteradapter){
  151. this.adapter=adapter;
  152. invalidateLayouts();
  153. invalidate();
  154. }
  155. /**
  156. *Setthethespecifiedscrollinginterpolator
  157. *@paraminterpolatortheinterpolator
  158. */
  159. publicvoidsetInterpolator(Interpolatorinterpolator){
  160. scroller.forceFinished(true);
  161. scroller=newScroller(getContext(),interpolator);
  162. }
  163. /**
  164. *Getscountofvisibleitems
  165. *
  166. *@returnthecountofvisibleitems
  167. */
  168. publicintgetVisibleItems(){
  169. returnvisibleItems;
  170. }
  171. /**
  172. *Setscountofvisibleitems
  173. *
  174. *@paramcount
  175. *thenewcount
  176. */
  177. publicvoidsetVisibleItems(intcount){
  178. visibleItems=count;
  179. invalidate();
  180. }
  181. /**
  182. *Getslabel
  183. *
  184. *@returnthelabel
  185. */
  186. publicStringgetLabel(){
  187. returnlabel;
  188. }
  189. /**
  190. *Setslabel
  191. *
  192. *@paramnewLabel
  193. *thelabeltoset
  194. */
  195. publicvoidsetLabel(StringnewLabel){
  196. if(label==null||!label.equals(newLabel)){
  197. label=newLabel;
  198. labelLayout=null;
  199. invalidate();
  200. }
  201. }
  202. /**
  203. *Addswheelchanginglistener
  204. *@paramlistenerthelistener
  205. */
  206. publicvoidaddChangingListener(OnWheelChangedListenerlistener){
  207. changingListeners.add(listener);
  208. }
  209. /**
  210. *Removeswheelchanginglistener
  211. *@paramlistenerthelistener
  212. */
  213. publicvoidremoveChangingListener(OnWheelChangedListenerlistener){
  214. changingListeners.remove(listener);
  215. }
  216. /**
  217. *Notifieschanginglisteners
  218. *@paramoldValuetheoldwheelvalue
  219. *@paramnewValuethenewwheelvalue
  220. */
  221. protectedvoidnotifyChangingListeners(intoldValue,intnewValue){
  222. for(OnWheelChangedListenerlistener:changingListeners){
  223. listener.onChanged(this,oldValue,newValue);
  224. }
  225. }
  226. /**
  227. *Addswheelscrollinglistener
  228. *@paramlistenerthelistener
  229. */
  230. publicvoidaddScrollingListener(OnWheelScrollListenerlistener){
  231. scrollingListeners.add(listener);
  232. }
  233. /**
  234. *Removeswheelscrollinglistener
  235. *@paramlistenerthelistener
  236. */
  237. publicvoidremoveScrollingListener(OnWheelScrollListenerlistener){
  238. scrollingListeners.remove(listener);
  239. }
  240. /**
  241. *Notifieslistenersaboutstartingscrolling
  242. */
  243. protectedvoidnotifyScrollingListenersAboutStart(){
  244. for(OnWheelScrollListenerlistener:scrollingListeners){
  245. listener.onScrollingStarted(this);
  246. }
  247. }
  248. /**
  249. *Notifieslistenersaboutendingscrolling
  250. */
  251. protectedvoidnotifyScrollingListenersAboutEnd(){
  252. for(OnWheelScrollListenerlistener:scrollingListeners){
  253. listener.onScrollingFinished(this);
  254. }
  255. }
  256. /**
  257. *Getscurrentvalue
  258. *
  259. *@returnthecurrentvalue
  260. */
  261. publicintgetCurrentItem(){
  262. returncurrentItem;
  263. }
  264. /**
  265. *Setsthecurrentitem.Doesnothingwhenindexiswrong.
  266. *
  267. *@paramindextheitemindex
  268. *@paramanimatedtheanimationflag
  269. */
  270. publicvoidsetCurrentItem(intindex,booleananimated){
  271. if(adapter==null||adapter.getItemsCount()==0){
  272. return;//throw?
  273. }
  274. if(index<0||index>=adapter.getItemsCount()){
  275. if(isCyclic){
  276. while(index<0){
  277. index+=adapter.getItemsCount();
  278. }
  279. index%=adapter.getItemsCount();
  280. }else{
  281. return;//throw?
  282. }
  283. }
  284. if(index!=currentItem){
  285. if(animated){
  286. scroll(index-currentItem,SCROLLING_DURATION);
  287. }else{
  288. invalidateLayouts();
  289. intold=currentItem;
  290. currentItem=index;
  291. notifyChangingListeners(old,currentItem);
  292. invalidate();
  293. }
  294. }
  295. }
  296. /**
  297. *Setsthecurrentitemw/oanimation.Doesnothingwhenindexiswrong.
  298. *
  299. *@paramindextheitemindex
  300. */
  301. publicvoidsetCurrentItem(intindex){
  302. setCurrentItem(index,false);
  303. }
  304. /**
  305. *Testsifwheeliscyclic.Thatmeansbeforethe1stitemthereisshownthelastone
  306. *@returntrueifwheeliscyclic
  307. */
  308. publicbooleanisCyclic(){
  309. returnisCyclic;
  310. }
  311. /**
  312. *Setwheelcyclicflag
  313. *@paramisCyclictheflagtoset
  314. */
  315. publicvoidsetCyclic(booleanisCyclic){
  316. this.isCyclic=isCyclic;
  317. invalidate();
  318. invalidateLayouts();
  319. }
  320. /**
  321. *Invalidateslayouts
  322. */
  323. privatevoidinvalidateLayouts(){
  324. itemsLayout=null;
  325. valueLayout=null;
  326. scrollingOffset=0;
  327. }
  328. /**
  329. *Initializesresources
  330. */
  331. privatevoidinitResourcesIfNecessary(){
  332. if(itemsPaint==null){
  333. itemsPaint=newTextPaint(Paint.ANTI_ALIAS_FLAG
  334. |Paint.FAKE_BOLD_TEXT_FLAG);
  335. //itemsPaint.density=getResources().getDisplayMetrics().density;
  336. itemsPaint.setTextSize(TEXT_SIZE);
  337. }
  338. if(valuePaint==null){
  339. valuePaint=newTextPaint(Paint.ANTI_ALIAS_FLAG
  340. |Paint.FAKE_BOLD_TEXT_FLAG|Paint.DITHER_FLAG);
  341. //valuePaint.density=getResources().getDisplayMetrics().density;
  342. valuePaint.setTextSize(TEXT_SIZE);
  343. valuePaint.setShadowLayer(0.1f,0,0.1f,0xFFC0C0C0);
  344. }
  345. if(centerDrawable==null){
  346. centerDrawable=getContext().getResources().getDrawable(R.drawable.wheel_val);
  347. }
  348. if(topShadow==null){
  349. topShadow=newGradientDrawable(Orientation.TOP_BOTTOM,SHADOWS_COLORS);
  350. }
  351. if(bottomShadow==null){
  352. bottomShadow=newGradientDrawable(Orientation.BOTTOM_TOP,SHADOWS_COLORS);
  353. }
  354. setBackgroundResource(R.drawable.wheel_bg);
  355. }
  356. /**
  357. *Calculatesdesiredheightforlayout
  358. *
  359. *@paramlayout
  360. *thesourcelayout
  361. *@returnthedesiredlayoutheight
  362. */
  363. privateintgetDesiredHeight(Layoutlayout){
  364. if(layout==null){
  365. return0;
  366. }
  367. intdesired=getItemHeight()*visibleItems-ITEM_OFFSET*2
  368. -ADDITIONAL_ITEM_HEIGHT;
  369. //Checkagainstourminimumheight
  370. desired=Math.max(desired,getSuggestedMinimumHeight());
  371. returndesired;
  372. }
  373. /**
  374. *Returnstextitembyindex
  375. *@paramindextheitemindex
  376. *@returntheitemornull
  377. */
  378. privateStringgetTextItem(intindex){
  379. if(adapter==null||adapter.getItemsCount()==0){
  380. returnnull;
  381. }
  382. intcount=adapter.getItemsCount();
  383. if((index<0||index>=count)&&!isCyclic){
  384. returnnull;
  385. }else{
  386. while(index<0){
  387. index=count+index;
  388. }
  389. }
  390. index%=count;
  391. returnadapter.getItem(index);
  392. }
  393. /**
  394. *Buildstextdependingoncurrentvalue
  395. *
  396. *@paramuseCurrentValue
  397. *@returnthetext
  398. */
  399. privateStringbuildText(booleanuseCurrentValue){
  400. StringBuilderitemsText=newStringBuilder();
  401. intaddItems=visibleItems/2+1;
  402. for(inti=currentItem-addItems;i<=currentItem+addItems;i++){
  403. if(useCurrentValue||i!=currentItem){
  404. Stringtext=getTextItem(i);
  405. if(text!=null){
  406. itemsText.append(text);
  407. }
  408. }
  409. if(i<currentItem+addItems){
  410. itemsText.append("\n");
  411. }
  412. }
  413. returnitemsText.toString();
  414. }
  415. /**
  416. *Returnsthemaxitemlengththatcanbepresent
  417. *@returnthemaxlength
  418. */
  419. privateintgetMaxTextLength(){
  420. WheelAdapteradapter=getAdapter();
  421. if(adapter==null){
  422. return0;
  423. }
  424. intadapterLength=adapter.getMaximumLength();
  425. if(adapterLength>0){
  426. returnadapterLength;
  427. }
  428. StringmaxText=null;
  429. intaddItems=visibleItems/2;
  430. for(inti=Math.max(currentItem-addItems,0);
  431. i<Math.min(currentItem+visibleItems,adapter.getItemsCount());i++){
  432. Stringtext=adapter.getItem(i);
  433. if(text!=null&&(maxText==null||maxText.length()<text.length())){
  434. maxText=text;
  435. }
  436. }
  437. returnmaxText!=null?maxText.length():0;
  438. }
  439. /**
  440. *Returnsheightofwheelitem
  441. *@returntheitemheight
  442. */
  443. privateintgetItemHeight(){
  444. if(itemHeight!=0){
  445. returnitemHeight;
  446. }elseif(itemsLayout!=null&&itemsLayout.getLineCount()>2){
  447. itemHeight=itemsLayout.getLineTop(2)-itemsLayout.getLineTop(1);
  448. returnitemHeight;
  449. }
  450. returngetHeight()/visibleItems;
  451. }
  452. /**
  453. *Calculatescontrolwidthandcreatestextlayouts
  454. *@paramwidthSizetheinputlayoutwidth
  455. *@parammodethelayoutmode
  456. *@returnthecalculatedcontrolwidth
  457. */
  458. privateintcalculateLayoutWidth(intwidthSize,intmode){
  459. initResourcesIfNecessary();
  460. intwidth=widthSize;
  461. intmaxLength=getMaxTextLength();
  462. if(maxLength>0){
  463. floattextWidth=FloatMath.ceil(Layout.getDesiredWidth("0",itemsPaint));
  464. itemsWidth=(int)(maxLength*textWidth);
  465. }else{
  466. itemsWidth=0;
  467. }
  468. itemsWidth+=ADDITIONAL_ITEMS_SPACE;//makeitsomemore
  469. labelWidth=0;
  470. if(label!=null&&label.length()>0){
  471. labelWidth=(int)FloatMath.ceil(Layout.getDesiredWidth(label,valuePaint));
  472. }
  473. booleanrecalculate=false;
  474. if(mode==MeasureSpec.EXACTLY){
  475. width=widthSize;
  476. recalculate=true;
  477. }else{
  478. width=itemsWidth+labelWidth+2*PADDING;
  479. if(labelWidth>0){
  480. width+=LABEL_OFFSET;
  481. }
  482. //Checkagainstourminimumwidth
  483. width=Math.max(width,getSuggestedMinimumWidth());
  484. if(mode==MeasureSpec.AT_MOST&&widthSize<width){
  485. width=widthSize;
  486. recalculate=true;
  487. }
  488. }
  489. if(recalculate){
  490. //recalculatewidth
  491. intpureWidth=width-LABEL_OFFSET-2*PADDING;
  492. if(pureWidth<=0){
  493. itemsWidth=labelWidth=0;
  494. }
  495. if(labelWidth>0){
  496. doublenewWidthItems=(double)itemsWidth*pureWidth
  497. /(itemsWidth+labelWidth);
  498. itemsWidth=(int)newWidthItems;
  499. labelWidth=pureWidth-itemsWidth;
  500. }else{
  501. itemsWidth=pureWidth+LABEL_OFFSET;//nolabel
  502. }
  503. }
  504. if(itemsWidth>0){
  505. createLayouts(itemsWidth,labelWidth);
  506. }
  507. returnwidth;
  508. }
  509. /**
  510. *Createslayouts
  511. *@paramwidthItemswidthofitemslayout
  512. *@paramwidthLabelwidthoflabellayout
  513. */
  514. privatevoidcreateLayouts(intwidthItems,intwidthLabel){
  515. if(itemsLayout==null||itemsLayout.getWidth()>widthItems){
  516. itemsLayout=newStaticLayout(buildText(isScrollingPerformed),itemsPaint,widthItems,
  517. widthLabel>0?Layout.Alignment.ALIGN_OPPOSITE:Layout.Alignment.ALIGN_CENTER,
  518. 1,ADDITIONAL_ITEM_HEIGHT,false);
  519. }else{
  520. itemsLayout.increaseWidthTo(widthItems);
  521. }
  522. if(!isScrollingPerformed&&(valueLayout==null||valueLayout.getWidth()>widthItems)){
  523. Stringtext=getAdapter()!=null?getAdapter().getItem(currentItem):null;
  524. valueLayout=newStaticLayout(text!=null?text:"",
  525. valuePaint,widthItems,widthLabel>0?
  526. Layout.Alignment.ALIGN_OPPOSITE:Layout.Alignment.ALIGN_CENTER,
  527. 1,ADDITIONAL_ITEM_HEIGHT,false);
  528. }elseif(isScrollingPerformed){
  529. valueLayout=null;
  530. }else{
  531. valueLayout.increaseWidthTo(widthItems);
  532. }
  533. if(widthLabel>0){
  534. if(labelLayout==null||labelLayout.getWidth()>widthLabel){
  535. labelLayout=newStaticLayout(label,valuePaint,
  536. widthLabel,Layout.Alignment.ALIGN_NORMAL,1,
  537. ADDITIONAL_ITEM_HEIGHT,false);
  538. }else{
  539. labelLayout.increaseWidthTo(widthLabel);
  540. }
  541. }
  542. }
  543. @Override
  544. protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){
  545. intwidthMode=MeasureSpec.getMode(widthMeasureSpec);
  546. intheightMode=MeasureSpec.getMode(heightMeasureSpec);
  547. intwidthSize=MeasureSpec.getSize(widthMeasureSpec);
  548. intheightSize=MeasureSpec.getSize(heightMeasureSpec);
  549. intwidth=calculateLayoutWidth(widthSize,widthMode);
  550. intheight;
  551. if(heightMode==MeasureSpec.EXACTLY){
  552. height=heightSize;
  553. }else{
  554. height=getDesiredHeight(itemsLayout);
  555. if(heightMode==MeasureSpec.AT_MOST){
  556. height=Math.min(height,heightSize);
  557. }
  558. }
  559. setMeasuredDimension(width,height);
  560. }
  561. @Override
  562. protectedvoidonDraw(Canvascanvas){
  563. super.onDraw(canvas);
  564. if(itemsLayout==null){
  565. if(itemsWidth==0){
  566. calculateLayoutWidth(getWidth(),MeasureSpec.EXACTLY);
  567. }else{
  568. createLayouts(itemsWidth,labelWidth);
  569. }
  570. }
  571. if(itemsWidth>0){
  572. canvas.save();
  573. //Skippaddingspaceandhideapartoftopandbottomitems
  574. canvas.translate(PADDING,-ITEM_OFFSET);
  575. drawItems(canvas);
  576. drawValue(canvas);
  577. canvas.restore();
  578. }
  579. drawCenterRect(canvas);
  580. drawShadows(canvas);
  581. }
  582. /**
  583. *Drawsshadowsontopandbottomofcontrol
  584. *@paramcanvasthecanvasfordrawing
  585. */
  586. privatevoiddrawShadows(Canvascanvas){
  587. topShadow.setBounds(0,0,getWidth(),getHeight()/visibleItems);
  588. topShadow.draw(canvas);
  589. bottomShadow.setBounds(0,getHeight()-getHeight()/visibleItems,
  590. getWidth(),getHeight());
  591. bottomShadow.draw(canvas);
  592. }
  593. /**
  594. *Drawsvalueandlabellayout
  595. *@paramcanvasthecanvasfordrawing
  596. */
  597. privatevoiddrawValue(Canvascanvas){
  598. valuePaint.setColor(VALUE_TEXT_COLOR);
  599. valuePaint.drawableState=getDrawableState();
  600. Rectbounds=newRect();
  601. itemsLayout.getLineBounds(visibleItems/2,bounds);
  602. //drawlabel
  603. if(labelLayout!=null){
  604. canvas.save();
  605. canvas.translate(itemsLayout.getWidth()+LABEL_OFFSET,bounds.top);
  606. labelLayout.draw(canvas);
  607. canvas.restore();
  608. }
  609. //drawcurrentvalue
  610. if(valueLayout!=null){
  611. canvas.save();
  612. canvas.translate(0,bounds.top+scrollingOffset);
  613. valueLayout.draw(canvas);
  614. canvas.restore();
  615. }
  616. }
  617. /**
  618. *Drawsitems
  619. *@paramcanvasthecanvasfordrawing
  620. */
  621. privatevoiddrawItems(Canvascanvas){
  622. canvas.save();
  623. inttop=itemsLayout.getLineTop(1);
  624. canvas.translate(0,-top+scrollingOffset);
  625. itemsPaint.setColor(ITEMS_TEXT_COLOR);
  626. itemsPaint.drawableState=getDrawableState();
  627. itemsLayout.draw(canvas);
  628. canvas.restore();
  629. }
  630. /**
  631. *Drawsrectforcurrentvalue
  632. *@paramcanvasthecanvasfordrawing
  633. */
  634. privatevoiddrawCenterRect(Canvascanvas){
  635. intcenter=getHeight()/2;
  636. intoffset=getItemHeight()/2;
  637. centerDrawable.setBounds(0,center-offset,getWidth(),center+offset);
  638. centerDrawable.draw(canvas);
  639. }
  640. @Override
  641. publicbooleanonTouchEvent(MotionEventevent){
  642. WheelAdapteradapter=getAdapter();
  643. if(adapter==null){
  644. returntrue;
  645. }
  646. if(!gestureDetector.onTouchEvent(event)&&event.getAction()==MotionEvent.ACTION_UP){
  647. justify();
  648. }
  649. returntrue;
  650. }
  651. /**
  652. *Scrollsthewheel
  653. *@paramdeltathescrollingvalue
  654. */
  655. privatevoiddoScroll(intdelta){
  656. scrollingOffset+=delta;
  657. intcount=scrollingOffset/getItemHeight();
  658. intpos=currentItem-count;
  659. if(isCyclic&&adapter.getItemsCount()>0){
  660. //fixpositionbyrotating
  661. while(pos<0){
  662. pos+=adapter.getItemsCount();
  663. }
  664. pos%=adapter.getItemsCount();
  665. }elseif(isScrollingPerformed){
  666. //
  667. if(pos<0){
  668. count=currentItem;
  669. pos=0;
  670. }elseif(pos>=adapter.getItemsCount()){
  671. count=currentItem-adapter.getItemsCount()+1;
  672. pos=adapter.getItemsCount()-1;
  673. }
  674. }else{
  675. //fixposition
  676. pos=Math.max(pos,0);
  677. pos=Math.min(pos,adapter.getItemsCount()-1);
  678. }
  679. intoffset=scrollingOffset;
  680. if(pos!=currentItem){
  681. setCurrentItem(pos,false);
  682. }else{
  683. invalidate();
  684. }
  685. //updateoffset
  686. scrollingOffset=offset-count*getItemHeight();
  687. if(scrollingOffset>getHeight()){
  688. scrollingOffset=scrollingOffset%getHeight()+getHeight();
  689. }
  690. }
  691. //gesturelistener
  692. privateSimpleOnGestureListenergestureListener=newSimpleOnGestureListener(){
  693. publicbooleanonDown(MotionEvente){
  694. if(isScrollingPerformed){
  695. scroller.forceFinished(true);
  696. clearMessages();
  697. returntrue;
  698. }
  699. returnfalse;
  700. }
  701. publicbooleanonScroll(MotionEvente1,MotionEvente2,floatdistanceX,floatdistanceY){
  702. startScrolling();
  703. doScroll((int)-distanceY);
  704. returntrue;
  705. }
  706. publicbooleanonFling(MotionEvente1,MotionEvente2,floatvelocityX,floatvelocityY){
  707. lastScrollY=currentItem*getItemHeight()+scrollingOffset;
  708. intmaxY=isCyclic?0x7FFFFFFF:adapter.getItemsCount()*getItemHeight();
  709. intminY=isCyclic?-maxY:0;
  710. scroller.fling(0,lastScrollY,0,(int)-velocityY/2,0,0,minY,maxY);
  711. setNextMessage(MESSAGE_SCROLL);
  712. returntrue;
  713. }
  714. };
  715. //Messages
  716. privatefinalintMESSAGE_SCROLL=0;
  717. privatefinalintMESSAGE_JUSTIFY=1;
  718. /**
  719. *Setnextmessagetoqueue.Clearsqueuebefore.
  720. *
  721. *@parammessagethemessagetoset
  722. */
  723. privatevoidsetNextMessage(intmessage){
  724. clearMessages();
  725. animationHandler.sendEmptyMessage(message);
  726. }
  727. /**
  728. *Clearsmessagesfromqueue
  729. */
  730. privatevoidclearMessages(){
  731. animationHandler.removeMessages(MESSAGE_SCROLL);
  732. animationHandler.removeMessages(MESSAGE_JUSTIFY);
  733. }
  734. //animationhandler
  735. privateHandleranimationHandler=newHandler(){
  736. publicvoidhandleMessage(Messagemsg){
  737. scroller.computeScrollOffset();
  738. intcurrY=scroller.getCurrY();
  739. intdelta=lastScrollY-currY;
  740. lastScrollY=currY;
  741. if(delta!=0){
  742. doScroll(delta);
  743. }
  744. //scrollingisnotfinishedwhenitcomestofinalY
  745. //so,finishitmanually
  746. if(Math.abs(currY-scroller.getFinalY())<MIN_DELTA_FOR_SCROLLING){
  747. currY=scroller.getFinalY();
  748. scroller.forceFinished(true);
  749. }
  750. if(!scroller.isFinished()){
  751. animationHandler.sendEmptyMessage(msg.what);
  752. }elseif(msg.what==MESSAGE_SCROLL){
  753. justify();
  754. }else{
  755. finishScrolling();
  756. }
  757. }
  758. };
  759. /**
  760. *Justifieswheel
  761. */
  762. privatevoidjustify(){
  763. if(adapter==null){
  764. return;
  765. }
  766. lastScrollY=0;
  767. intoffset=scrollingOffset;
  768. intitemHeight=getItemHeight();
  769. booleanneedToIncrease=offset>0?currentItem<adapter.getItemsCount():currentItem>0;
  770. if((isCyclic||needToIncrease)&&Math.abs((float)offset)>(float)itemHeight/2){
  771. if(offset<0)
  772. offset+=itemHeight+MIN_DELTA_FOR_SCROLLING;
  773. else
  774. offset-=itemHeight+MIN_DELTA_FOR_SCROLLING;
  775. }
  776. if(Math.abs(offset)>MIN_DELTA_FOR_SCROLLING){
  777. scroller.startScroll(0,0,0,offset,SCROLLING_DURATION);
  778. setNextMessage(MESSAGE_JUSTIFY);
  779. }else{
  780. finishScrolling();
  781. }
  782. }
  783. /**
  784. *Startsscrolling
  785. */
  786. privatevoidstartScrolling(){
  787. if(!isScrollingPerformed){
  788. isScrollingPerformed=true;
  789. notifyScrollingListenersAboutStart();
  790. }
  791. }
  792. /**
  793. *Finishesscrolling
  794. */
  795. voidfinishScrolling(){
  796. if(isScrollingPerformed){
  797. notifyScrollingListenersAboutEnd();
  798. isScrollingPerformed=false;
  799. }
  800. invalidateLayouts();
  801. invalidate();
  802. }
  803. /**
  804. *Scrollthewheel
  805. *@paramitemsToSkipitemstoscroll
  806. *@paramtimescrollingduration
  807. */
  808. publicvoidscroll(intitemsToScroll,inttime){
  809. scroller.forceFinished(true);
  810. lastScrollY=scrollingOffset;
  811. intoffset=itemsToScroll*getItemHeight();
  812. scroller.startScroll(0,lastScrollY,0,offset-lastScrollY,time);
  813. setNextMessage(MESSAGE_SCROLL);
  814. startScrolling();
  815. }
  816. }

主布局文件

view plain
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_height="wrap_content"
  4. android:orientation="vertical"
  5. android:background="@drawable/layout_bg"
  6. android:layout_width="fill_parent">
  7. <TextView
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:layout_marginTop="24dp"
  11. android:layout_gravity="center_horizontal"
  12. android:textSize="20sp"
  13. android:textStyle="bold"
  14. android:text="PleaseenterPIN"/>
  15. <LinearLayout
  16. android:layout_marginTop="24dp"
  17. android:layout_gravity="center_horizontal"
  18. android:layout_width="wrap_content"
  19. android:layout_height="wrap_content">
  20. <kankan.wheel.widget.WheelViewandroid:id="@+id/passw_1"
  21. android:layout_height="wrap_content"
  22. android:layout_width="wrap_content"/>
  23. <kankan.wheel.widget.WheelViewandroid:id="@+id/passw_2"
  24. android:layout_height="wrap_content"
  25. android:layout_width="wrap_content"/>
  26. <kankan.wheel.widget.WheelViewandroid:id="@+id/passw_3"
  27. android:layout_height="wrap_content"
  28. android:layout_width="wrap_content"/>
  29. <kankan.wheel.widget.WheelViewandroid:id="@+id/passw_4"
  30. android:layout_height="wrap_content"
  31. android:layout_width="wrap_content"/>
  32. <kankan.wheel.widget.WheelViewandroid:id="@+id/passw_5"
  33. android:layout_height="wrap_content"
  34. android:layout_width="wrap_content"/>
  35. <kankan.wheel.widget.WheelViewandroid:id="@+id/passw_6"
  36. android:layout_height="wrap_content"
  37. android:layout_width="wrap_content"/>
  38. </LinearLayout>
  39. <TextViewandroid:id="@+id/pwd_status"
  40. android:layout_width="wrap_content"
  41. android:layout_height="wrap_content"
  42. android:layout_marginTop="24dp"
  43. android:layout_gravity="center_horizontal"
  44. android:textSize="18sp"
  45. android:textColor="#FFF"
  46. android:text="WrongPIN"/>
  47. <Buttonandroid:id="@+id/btn_mix"
  48. android:layout_width="wrap_content"
  49. android:layout_height="wrap_content"
  50. android:layout_gravity="center_horizontal"
  51. android:layout_marginTop="12dp"
  52. android:textSize="18sp"
  53. android:text="Mix"/>
  54. </LinearLayout>


适配器adapter

view plain
  1. /*
  2. *Copyright2010YuriKanivets
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. packagekankan.wheel.widget;
  17. publicinterfaceWheelAdapter{
  18. /**
  19. *Getsitemscount
  20. *@returnthecountofwheelitems
  21. */
  22. publicintgetItemsCount();
  23. /**
  24. *Getsawheelitembyindex.
  25. *
  26. *@paramindextheitemindex
  27. *@returnthewheelitemtextornull
  28. */
  29. publicStringgetItem(intindex);
  30. /**
  31. *Getsmaximumitemlength.Itisusedtodeterminethewheelwidth.
  32. *If-1isreturnedtherewillbeusedthedefaultwheelwidth.
  33. *
  34. *@returnthemaximumitemlengthor-1
  35. */
  36. publicintgetMaximumLength();
  37. }



view plain
  1. /*
  2. *Copyright2010YuriKanivets
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. packagekankan.wheel.widget;
  17. /**
  18. *NumericWheeladapter.
  19. */
  20. publicclassNumericWheelAdapterimplementsWheelAdapter{
  21. /**Thedefaultminvalue*/
  22. publicstaticfinalintDEFAULT_MAX_VALUE=9;
  23. /**Thedefaultmaxvalue*/
  24. privatestaticfinalintDEFAULT_MIN_VALUE=0;
  25. //Values
  26. privateintminValue;
  27. privateintmaxValue;
  28. //format
  29. privateStringformat;
  30. /**
  31. *Defaultconstructor
  32. */
  33. publicNumericWheelAdapter(){
  34. this(DEFAULT_MIN_VALUE,DEFAULT_MAX_VALUE);
  35. }
  36. /**
  37. *Constructor
  38. *@paramminValuethewheelminvalue
  39. *@parammaxValuethewheelmaxvalue
  40. */
  41. publicNumericWheelAdapter(intminValue,intmaxValue){
  42. this(minValue,maxValue,null);
  43. }
  44. /**
  45. *Constructor
  46. *@paramminValuethewheelminvalue
  47. *@parammaxValuethewheelmaxvalue
  48. *@paramformattheformatstring
  49. */
  50. publicNumericWheelAdapter(intminValue,intmaxValue,Stringformat){
  51. this.minValue=minValue;
  52. this.maxValue=maxValue;
  53. this.format=format;
  54. }
  55. @Override
  56. publicStringgetItem(intindex){
  57. if(index>=0&&index<getItemsCount()){
  58. intvalue=minValue+index;
  59. returnformat!=null?String.format(format,value):Integer.toString(value);
  60. }
  61. returnnull;
  62. }
  63. @Override
  64. publicintgetItemsCount(){
  65. returnmaxValue-minValue+1;
  66. }
  67. @Override
  68. publicintgetMaximumLength(){
  69. intmax=Math.max(Math.abs(maxValue),Math.abs(minValue));
  70. intmaxLen=Integer.toString(max).length();
  71. if(minValue<0){
  72. maxLen++;
  73. }
  74. returnmaxLen;
  75. }
  76. }


监听器Listener文件:

view plain
  1. /*
  2. *Copyright2010YuriKanivets
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. packagekankan.wheel.widget;
  17. /**
  18. *Wheelscrolledlistenerinterface.
  19. */
  20. publicinterfaceOnWheelScrollListener{
  21. /**
  22. *Callbackmethodtobeinvokedwhenscrollingstarted.
  23. *@paramwheelthewheelviewwhosestatehaschanged.
  24. */
  25. voidonScrollingStarted(WheelViewwheel);
  26. /**
  27. *Callbackmethodtobeinvokedwhenscrollingended.
  28. *@paramwheelthewheelviewwhosestatehaschanged.
  29. */
  30. voidonScrollingFinished(WheelViewwheel);
  31. }


view plain
  1. /*
  2. *Copyright2010YuriKanivets
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. packagekankan.wheel.widget;
  17. /**
  18. *Wheelchangedlistenerinterface.
  19. *<p>ThecurrentItemChanged()methodiscalledwhenevercurrentwheelpositionsischanged:
  20. *<li>NewWheelpositionisset
  21. *<li>Wheelviewisscrolled
  22. */
  23. publicinterfaceOnWheelChangedListener{
  24. /**
  25. *Callbackmethodtobeinvokedwhencurrentitemchanged
  26. *@paramwheelthewheelviewwhosestatehaschanged
  27. *@paramoldValuetheoldvalueofcurrentitem
  28. *@paramnewValuethenewvalueofcurrentitem
  29. */
  30. voidonChanged(WheelViewwheel,intoldValue,intnewValue);
  31. }

更多相关文章

  1. android(11)_文件操作读取模式
  2. android 关于 ScrollView嵌套GridView,ListView 显示和滑动的问题
  3. android中常用的方法备忘
  4. Android中JNI程序的编写(zhuan)
  5. (转)Android(安卓)TextView背景色、圆角、内部填充设置
  6. 使用libevent实现最简单的android http-server
  7. Eclipse,到了说再见的时候了——Android(安卓)Studio最全解析
  8. android 混淆后的代码还原
  9. Android实现 ScrollView + ListView无滚动条滚动

随机推荐

  1. Android2.1读取进程流量
  2. Android(安卓)中LayoutInflater的使用
  3. Android(安卓)Room 框架学习
  4. 【Android】ImageButton的记录
  5. android-对话式聊天效果实现
  6. 关于android中alarm的使用
  7. Android(安卓)适配Q版本Beta2
  8. Android两行代码搞定ViewPager的过渡动画
  9. android P系统访问http请求最简单解决方
  10. Android(安卓)kotlin 之 Fragment获取控