Android 實現 WheelView

來源:互聯網
上載者:User

我們都知道,在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的完整實現代碼如下:
package com.nj1s.lib.widget;import android.content.Context;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.graphics.drawable.GradientDrawable;import android.graphics.drawable.GradientDrawable.Orientation;import android.util.AttributeSet;import android.view.Gravity;import android.view.View;import com.nj1s.lib.R;public class WheelView extends TosGallery{    private Drawable mSelectorDrawable      = null;    private Rect mSelectorBound             = new Rect();    private GradientDrawable mTopShadow     = null;    private GradientDrawable mBottomShadow  = null;    private static final int[] SHADOWS_COLORS =    {        0xFF111111,        0x00AAAAAA,        0x00AAAAAA    };    public WheelView(Context context)    {        super(context);        initialize(context);    }    public WheelView(Context context, AttributeSet attrs)    {        super(context, attrs);        initialize(context);    }    public WheelView(Context context, AttributeSet attrs, int defStyle)    {        super(context, attrs, defStyle);        initialize(context);    }    private void initialize(Context context)    {        this.setVerticalScrollBarEnabled(false);        this.setSlotInCenter(true);        this.setOrientation(TosGallery.VERTICAL);        this.setGravity(Gravity.CENTER_HORIZONTAL);        this.setUnselectedAlpha(1.0f);        // This lead the onDraw() will be called.        this.setWillNotDraw(false);        // The selector rectangle drawable.        this.mSelectorDrawable =             getContext().getResources().getDrawable(R.drawable.wheel_val);        this.mTopShadow    =             new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS);        this.mBottomShadow =             new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS);        // The default background.        this.setBackgroundResource(R.drawable.wheel_bg);    }    @Override    protected void dispatchDraw(Canvas canvas)    {        super.dispatchDraw(canvas);        // After draw child, we do the following things:        // +1, Draw the center rectangle.        // +2, Draw the shadows on the top and bottom.        drawCenterRect(canvas);        drawShadows(canvas);    }    /**     * setOrientation     */    @Override    public void setOrientation(int orientation)    {        if (TosGallery.HORIZONTAL == orientation)        {            throw new IllegalArgumentException("The orientation must be VERTICAL");        }        super.setOrientation(orientation);    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b)    {        super.onLayout(changed, l, t, r, b);        int galleryCenter = getCenterOfGallery();        View v = this.getChildAt(0);        int height = (null != v) ? v.getMeasuredHeight() : 50;        int top = galleryCenter - height / 2;        int bottom = top + height;        mSelectorBound.set(                getPaddingLeft(),                top,                getWidth() - getPaddingRight(),                bottom);    }    private void drawCenterRect(Canvas canvas)    {        if (null != mSelectorDrawable)        {            mSelectorDrawable.setBounds(mSelectorBound);            mSelectorDrawable.draw(canvas);        }    }    private void drawShadows(Canvas canvas)    {        int height = (int)(2.0 * mSelectorBound.height());        mTopShadow.setBounds(0, 0, getWidth(), height);        mTopShadow.draw(canvas);        mBottomShadow.setBounds(0, getHeight() - height, getWidth(), getHeight());        mBottomShadow.draw(canvas);    }}

上面代碼沒有什麼特別的東西,只是有幾點需要注意:[1] 不要重寫onDraw(),為什麼呢?因為onDraw()是繪製自己,如果你在onDraw()中來繪製陰影的話,那麼最後的效果可能是Child在上面,陰影在下面。因此,我們應該是在繪製完Child之後,再繪製陰影,怎麼做呢?請看第二步。[2] 重寫dispatchDraw(),如果對這個方法不明白的話,請自己看文檔,這裡不解釋,總之,這個方法是用來繪製Child的,因此,重寫這個方法,先調用super.dispatchDraw()方法,然後再繪製陰影,OK,萬事大吉。[3] 你可以調用#setScrollCycle(boolean)來指定這個WheelView是否可以迴圈滑動。5. 如何使用關於如何使用,其實很簡單,就跟使用GridView/ListView一樣,通過Adapter來提供View。

// 設定listenermDateWheel.setOnEndFlingListener(mListener);// 設定滑動時的聲音mDateWheel.setSoundEffectsEnabled(true);// 設定adaptermDateWheel.setAdapter(new WheelTextAdapter(this));// Adapter的實現protected class WheelTextAdapter extends BaseAdapter{    ArrayList<TextInfo> mData = null;    int mWidth  = ViewGroup.LayoutParams.MATCH_PARENT;    int mHeight = 50;    Context mContext = null;        public WheelTextAdapter(Context context)    {        mContext = context;    }        public void setData(ArrayList<TextInfo> data)    {        mData = data;        this.notifyDataSetChanged();    }        public void setItemSize(int width, int height)    {        mWidth  = width;        mHeight = height;    }        @Override    public int getCount()    {        return (null != mData) ? mData.size() : 0;    }    @Override    public Object getItem(int position)    {        return null;    }    @Override    public long getItemId(int position)    {        return 0;    }    @Override    public View getView(int position, View convertView, ViewGroup parent)    {        TextView textView = null;                if (null == convertView)        {            convertView = new TextView(mContext);            convertView.setLayoutParams(new TosGallery.LayoutParams(mWidth, mHeight));            textView = (TextView)convertView;            textView.setGravity(Gravity.CENTER);            textView.setTextSize(26);            textView.setTextColor(Color.BLACK);        }                if (null == textView)        {            textView = (TextView)convertView;        }                TextInfo info = mData.get(position);        textView.setText(info.mText);        textView.setTextColor(info.mColor);                return convertView;    }}
如果大家感興趣,可以給我發郵件要原始碼,我的郵箱是: leehong2005@163.com
這個是《UEFA.com新聞用戶端》,大家關注一下,謝謝 http://apk.hiapk.com/html/2013/06/1511803.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.