• Android 实现 WheelView


    我们都知道,在iOS里面有一种控件------滚筒控件(Wheel View),这通常用于设置时间/日期,非常方便,但Android SDK并没有提供类似的控件。这里介绍一下如何Android实现WheelView。

    源码下载请点我

    先来看一看iOS中的WheelView的效果图:


    这个效果不错吧,我们应该如何实现呢?

    那在Android如果也要实现这样一个效果,应该怎么做呢?

    1.Android WheelView效果图


    上图是我实现的DEMO的运行效果图。


    2.网上的开源代码

    我们从网上找到了一个开源的代码,它也实现了这样的效果,而且效果也不错,大家可以用SVN来checkout:

    http://android-wheel.googlecode.com/svn/trunk

    它这个Demo最本质是自己写布局,好像是利用一个LinearLayout来布局child,然后调用LinearLayout.draw(canvas)方法,把child绘制在指定的canvas上面。它同时还提供了类似AdapterView的访问方式,用户可以设置Adapter来提供数据。我在这里主要不是讲解这个Demo的结构,如果大家感兴趣,可以自己下载代码研究。


    3.实现思路

    由于网上的Demo也是提供了类似于AdapterView的访问方式,所以,我在想,我们能不能换一种方式来实现,试想,如果这个滚筒是横着的,那么我们就可以利用Gallery来实现,Gallery的特点跟WheelView有相似之处,比如:选中的项始终在View中间,只不过它是横着布局的。

    由于我之前修改过Gallery的源代码,可以使其循环滚动,并且第一个child可以排列在最左端,所以,我在想,如果我能把Gallery修改成竖的(垂直排列),那这个不就是OK了吗?基于这样的想法,我就准备修改代码了。

    我们这里需要把Gallery的源码复制到我们的工程中,然后修改,保证能编译通过。

    与Gallery相关的的几个文件如下所示,它们都是放在widget文件夹和res/value文件夹下面。

    • AbsSpinner.java
    • AdapterView.java
    • Gallery.java
    • attr.xml

    修改的过程比较麻烦,我这里不详细说明(要细说的话,内容太多了),在修改之后,我们的Gallery提供了一个方法:setOrientation(int),你可以让这个Gallery水平滑动,也可以垂直滑动。

    我们还应该提供以下几个核心方法:

    • setOnEndFlingListener ------ 当Gallery停止滑动时的回调用,这样调用者可以在停止滑动时来得到当前选中的项。
    • setOrientation(int) ------ 支持布局方向:HORIZONTAL和VERTICAL。
    • setScrollCycle(boolean) ------ 是否支持循环滑动。
    • setSlotInCenter(boolean) ------ 是否让Gallery选中的项居中。

    4. 扩展Gallery

    在修改完Gallery后,我们就可以来使用它了,还得做一些事情,就是先要扩展Gallery,实现一个WheelView,在这个类里面,我们要去绘制中间选择的矩形、背景图片、上下阴影等。
    这个WheelView扩展了Gallery,同时还应该提供设置背景图片,选择矩形的图片和上下阴影的图片等功能。
    WheelView的完整实现代码如下:

    [java] view plaincopy
    1. package com.nj1s.lib.widget;  
    2.   
    3. import android.content.Context;  
    4. import android.graphics.Canvas;  
    5. import android.graphics.Rect;  
    6. import android.graphics.drawable.Drawable;  
    7. import android.graphics.drawable.GradientDrawable;  
    8. import android.graphics.drawable.GradientDrawable.Orientation;  
    9. import android.util.AttributeSet;  
    10. import android.view.Gravity;  
    11. import android.view.View;  
    12.   
    13. import com.nj1s.lib.R;  
    14.   
    15. public class WheelView extends TosGallery  
    16. {  
    17.     private Drawable mSelectorDrawable      = null;  
    18.     private Rect mSelectorBound             = new Rect();  
    19.     private GradientDrawable mTopShadow     = null;  
    20.     private GradientDrawable mBottomShadow  = null;  
    21.     private static final int[] SHADOWS_COLORS =  
    22.     {  
    23.         0xFF111111,  
    24.         0x00AAAAAA,  
    25.         0x00AAAAAA  
    26.     };  
    27.   
    28.     public WheelView(Context context)  
    29.     {  
    30.         super(context);  
    31.   
    32.         initialize(context);  
    33.     }  
    34.   
    35.     public WheelView(Context context, AttributeSet attrs)  
    36.     {  
    37.         super(context, attrs);  
    38.   
    39.         initialize(context);  
    40.     }  
    41.   
    42.     public WheelView(Context context, AttributeSet attrs, int defStyle)  
    43.     {  
    44.         super(context, attrs, defStyle);  
    45.   
    46.         initialize(context);  
    47.     }  
    48.   
    49.     private void initialize(Context context)  
    50.     {  
    51.         this.setVerticalScrollBarEnabled(false);  
    52.         this.setSlotInCenter(true);  
    53.         this.setOrientation(TosGallery.VERTICAL);  
    54.         this.setGravity(Gravity.CENTER_HORIZONTAL);  
    55.         this.setUnselectedAlpha(1.0f);  
    56.   
    57.         // This lead the onDraw() will be called.  
    58.         this.setWillNotDraw(false);  
    59.   
    60.         // The selector rectangle drawable.  
    61.         this.mSelectorDrawable =   
    62.             getContext().getResources().getDrawable(R.drawable.wheel_val);  
    63.         this.mTopShadow    =   
    64.             new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS);  
    65.         this.mBottomShadow =   
    66.             new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS);  
    67.   
    68.         // The default background.  
    69.         this.setBackgroundResource(R.drawable.wheel_bg);  
    70.     }  
    71.   
    72.     @Override  
    73.     protected void dispatchDraw(Canvas canvas)  
    74.     {  
    75.         super.dispatchDraw(canvas);  
    76.   
    77.         // After draw child, we do the following things:  
    78.         // +1, Draw the center rectangle.  
    79.         // +2, Draw the shadows on the top and bottom.  
    80.   
    81.         drawCenterRect(canvas);  
    82.   
    83.         drawShadows(canvas);  
    84.     }  
    85.   
    86.     /** 
    87.      * setOrientation 
    88.      */  
    89.     @Override  
    90.     public void setOrientation(int orientation)  
    91.     {  
    92.         if (TosGallery.HORIZONTAL == orientation)  
    93.         {  
    94.             throw new IllegalArgumentException("The orientation must be VERTICAL");  
    95.         }  
    96.   
    97.         super.setOrientation(orientation);  
    98.     }  
    99.   
    100.     @Override  
    101.     protected void onLayout(boolean changed, int l, int t, int r, int b)  
    102.     {  
    103.         super.onLayout(changed, l, t, r, b);  
    104.   
    105.         int galleryCenter = getCenterOfGallery();  
    106.         View v = this.getChildAt(0);  
    107.   
    108.         int height = (null != v) ? v.getMeasuredHeight() : 50;  
    109.         int top = galleryCenter - height / 2;  
    110.         int bottom = top + height;  
    111.   
    112.         mSelectorBound.set(  
    113.                 getPaddingLeft(),  
    114.                 top,  
    115.                 getWidth() - getPaddingRight(),  
    116.                 bottom);  
    117.     }  
    118.   
    119.     private void drawCenterRect(Canvas canvas)  
    120.     {  
    121.         if (null != mSelectorDrawable)  
    122.         {  
    123.             mSelectorDrawable.setBounds(mSelectorBound);  
    124.             mSelectorDrawable.draw(canvas);  
    125.         }  
    126.     }  
    127.   
    128.     private void drawShadows(Canvas canvas)  
    129.     {  
    130.         int height = (int)(2.0 * mSelectorBound.height());  
    131.         mTopShadow.setBounds(00, getWidth(), height);  
    132.         mTopShadow.draw(canvas);  
    133.   
    134.         mBottomShadow.setBounds(0, getHeight() - height, getWidth(), getHeight());  
    135.         mBottomShadow.draw(canvas);  
    136.     }  
    137. }  

    上面代码没有什么特别的东西,只是有几点需要注意:

    [1] 不要重写onDraw(),为什么呢?因为onDraw()是绘制自己,如果你在onDraw()中来绘制阴影的话,那么最后的效果可能是Child在上面,阴影在下面。因此,我们应该是在绘制完Child之后,再绘制阴影,怎么做呢?请看第二步。

    [2] 重写dispatchDraw(),如果对这个方法不明白的话,请自己看文档,这里不解释,总之,这个方法是用来绘制Child的,因此,重写这个方法,先调用super.dispatchDraw()方法,然后再绘制阴影,OK,万事大吉。

    [3] 你可以调用#setScrollCycle(boolean)来指定这个WheelView是否可以循环滑动。


    5. 如何使用

    关于如何使用,其实很简单,就跟使用GridView/ListView一样,通过Adapter来提供View。

    [java] view plaincopy
    1. // 设置listener  
    2. mDateWheel.setOnEndFlingListener(mListener);  
    3. // 设置滑动时的声音  
    4. mDateWheel.setSoundEffectsEnabled(true);  
    5. // 设置adapter  
    6. mDateWheel.setAdapter(new WheelTextAdapter(this));  
    7.   
    8.   
    9. // Adapter的实现  
    10. protected class WheelTextAdapter extends BaseAdapter  
    11. {  
    12.     ArrayList<TextInfo> mData = null;  
    13.     int mWidth  = ViewGroup.LayoutParams.MATCH_PARENT;  
    14.     int mHeight = 50;  
    15.     Context mContext = null;  
    16.       
    17.     public WheelTextAdapter(Context context)  
    18.     {  
    19.         mContext = context;  
    20.     }  
    21.       
    22.     public void setData(ArrayList<TextInfo> data)  
    23.     {  
    24.         mData = data;  
    25.         this.notifyDataSetChanged();  
    26.     }  
    27.       
    28.     public void setItemSize(int width, int height)  
    29.     {  
    30.         mWidth  = width;  
    31.         mHeight = height;  
    32.     }  
    33.       
    34.     @Override  
    35.     public int getCount()  
    36.     {  
    37.         return (null != mData) ? mData.size() : 0;  
    38.     }  
    39.   
    40.   
    41.     @Override  
    42.     public Object getItem(int position)  
    43.     {  
    44.         return null;  
    45.     }  
    46.   
    47.   
    48.     @Override  
    49.     public long getItemId(int position)  
    50.     {  
    51.         return 0;  
    52.     }  
    53.   
    54.   
    55.     @Override  
    56.     public View getView(int position, View convertView, ViewGroup parent)  
    57.     {  
    58.         TextView textView = null;  
    59.           
    60.         if (null == convertView)  
    61.         {  
    62.             convertView = new TextView(mContext);  
    63.             convertView.setLayoutParams(new TosGallery.LayoutParams(mWidth, mHeight));  
    64.             textView = (TextView)convertView;  
    65.             textView.setGravity(Gravity.CENTER);  
    66.             textView.setTextSize(26);  
    67.             textView.setTextColor(Color.BLACK);  
    68.         }  
    69.           
    70.         if (null == textView)  
    71.         {  
    72.             textView = (TextView)convertView;  
    73.         }  
    74.           
    75.         TextInfo info = mData.get(position);  
    76.         textView.setText(info.mText);  
    77.         textView.setTextColor(info.mColor);  
    78.           
    79.         return convertView;  
    80.     }  
    81. }  
    如果大家感兴趣,可以给我发邮件要源代码,我的邮箱是:leehong2005@163.com

    这个是《UEFA.com新闻客户端》,大家关注一下,谢谢

    原文地址:http://blog.csdn.net/leehong2005/article/details/8623694
    作者:郭耀华
    出处:http://www.guoyaohua.com
    微信:guoyaohua167
    邮箱:guo.yaohua@foxmail.com
    本文版权归作者和博客园所有,欢迎转载,转载请标明出处。
    【如果你觉得本文还不错,对你的学习带来了些许帮助,请帮忙点击右下角的推荐】

    dashang
  • 相关阅读:
    前端学习之JavaScript
    前端学习之CSS
    前端学习之HTML
    MySQL多表查询(重要)
    C# 基本语法
    第 9 章 —— 原型模式
    第 7 章 —— 代理模式
    第 6 章 —— 装饰模式
    将搜索关键词加红
    SQL Server 创建触发器(trigger)
  • 原文地址:https://www.cnblogs.com/guoyaohua/p/8502937.html
Copyright © 2020-2023  润新知