Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android梳理不常用widget篇

Android梳理不常用widget篇

編輯:關於Android編程

閒得蛋疼,折騰折騰android源碼包下面widget包下面很少用以及幾乎沒聽說過的控件(針對自己而言,莫要批斗(⊙o⊙)哦丫)。


TextClock

效果圖

\

實現原理

TextClock繼承自TextView,擴展自定義屬性三個(主要是顯示格式相關屬性控制)

\

在onAttachedToWindow和onDetachedFromWindow方法注冊了廣播和取消注冊,監聽時間發生變化了,接收到廣播,調用onTimeChanged方法更新UI,下面是簡要代碼塊

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        if (!mAttached) {
            mAttached = true;

            registerReceiver();
           // .................略....................
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();

        if (mAttached) {
            unregisterReceiver();
           // .................略....................
        }
    }

    private void registerReceiver() {
        final IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_TIME_TICK);
        filter.addAction(Intent.ACTION_TIME_CHANGED);
        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
        getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
    }

    private void unregisterReceiver() {
        getContext().unregisterReceiver(mIntentReceiver);
    }

    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (mTimeZone == null &&    Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
                final String timeZone = intent.getStringExtra("time-zone");
                createTime(timeZone);
            }
            onTimeChanged();
        }
    };
    private void onTimeChanged() {
        mTime.setTimeInMillis(System.currentTimeMillis());
        setText(DateFormat.format(mFormat, mTime));
        setContentDescription(DateFormat.format(mDescFormat, mTime));
    }

Space

效果圖

\

實現原理

Space控件繼承自View,在構造函數直接把控件設置為INVISIBLE模式,修改測量方法onMeasure,取消了draw方法的canvas繪制渲染的處理,下面是測量寬高相關核心代碼

 private static int getDefaultSize2(int size, int measureSpec) {
        int result = size;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
            case MeasureSpec.UNSPECIFIED:
                result = size;
                break;
            case MeasureSpec.AT_MOST:
                result = Math.min(size, specSize);
                break;
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;
        }
        return result;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(
                getDefaultSize2(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize2(getSuggestedMinimumHeight(), heightMeasureSpec));
    }

如果在以前你喜歡用View控件,setVisiblity占用屏幕空間,建議以後替換成Space控件,好處在於draw方法的重寫,具體不解釋。

ZoomButton 、ZoomControls

效果圖

\

實現原理

ZoomButton內部就一個核心點,設置ZoomSpeed,默認速度值1000,ZoomControl是一個自定義的ViewGroup,布局控件默認inflater預先定義好的布局,如下


    
    

如果你想改變著丑陋的UI,你可以嘗試拷貝源碼出來,修改Inflater的布局即可。這個空間提供的show 、hide方法只是在執行透明動畫,關鍵代碼塊如下

  public void show() {
        fade(View.VISIBLE, 0.0f, 1.0f);
    }

    public void hide() {
        fade(View.GONE, 1.0f, 0.0f);
    }

    private void fade(int visibility, float startAlpha, float endAlpha) {
        AlphaAnimation anim = new AlphaAnimation(startAlpha, endAlpha);
        anim.setDuration(500);
        startAnimation(anim);
        setVisibility(visibility);
    }

該類對ZoomSpeed值提供了一個方法setZoomSpeed設置,其他的沒什麼好關注的,Listener的監聽回調也略過吧,就這樣吧。(merge沒用過的可以去了解一下)

AdapterViewAnimator、AdapterViewFlipper、StackView

效果圖

\

實現原理

AdapterViewFlipper可以實現輪播圖片,雖然有點撇腳,不能手動滑動,也無法感知輪播到了那個界面,關於這一點可以重寫控件,修改showNext回調位置,至於手動滑動需要手勢攔截處理這塊怎麼說呢,你若有興趣自己造輪子可以試試。

這裡要區別兩個類:ViewFlipper和AdapterViewFlipper,這是兩個不同的類,下面是他們的繼承體系

\

AdapterViewFlipper的自定義屬性在他的父類有定義自己也有定義,下面來看看具體的含義與代碼調用方法

下面是對照自定義屬性的說明和方法調用

自定義屬性 注釋 對應方法 inAnimation 組件顯示時用的動畫 setInAnimation() outAnimation 組件隱藏時用的動畫 setInAnimation() animateFirstView 組件顯示第一個View時是否播放動畫 setAnimateFirstView(),默認播放動畫 loopViews 循環到最後一個視圖是否回到第一個視圖 AdapterViewFlipper強制設為了true flipInterval 循環播放動畫時間間隔 setFlipInterval()默認1000間隔 autoStart 是否自動播放動畫 setAutoStart()

當你使用默認播放動畫切換視圖感覺不是1秒,不要覺得奇怪,動畫執行也需要時間的,默認in 、out 動畫時常都是200。對於代碼功能性調用來說我們只需要關注下面這幾個方法即可

\

startFlipping開啟輪播沒啥好說的,該類同樣使用了上面提到的注冊廣播,注冊了屏幕關閉和喚醒廣播,關閉屏幕就暫停輪播,喚醒時如果之前是輪播狀態,那麼繼續開始輪播。(相關代碼塊就不貼,自己查看源代碼)

StackView雖說也是AdapterViewAnimator子類,但是其實現效果與AdapterViewFlipper不同,具體效果圖就不貼了,實在是原生控件在實際得出的效果拿不出手,而且感覺在應用場景上來說也找不到對應的,於是乎在github檢索了一會,找到了一個還算不錯的開源,下面是地址和效果圖:https://github.com/blipinsk/FlippableStackView

\

QuickContactBadge

這個ImageView的擴展可以簡單的了解一下,推薦農民伯伯大神博客地址:http://www.cnblogs.com/over140/archive/2010/09/28/1837287.html,開發中用的比較少,大概看看就行了

ViewAnimator、ViewFlipper、ViewSwitcher、TextSwitcher

ViewFlipper、ViewSwitcher都是繼承自ViewAnimator,ViewFlipper與AdapterViewFlipper差別不大略過,這裡主要是關注一下ViewSwitcher相關類擴展一下視野。ViewAnimator是繼承自FrameLayout,而ViewSwitcher是其子類,強制有且只能有2個childView,TextSwitcher限定childView必須是TextView.關於這類擴展控件自行檢索Github.

Spinner、AbsSpinner、AdapterView、AutoCompleteTextView、MultiAutoCompleteTextView、ListPopupWindow、ListView到底有多親密的關系?

直接貼代碼估計比較晦澀難懂了,能把人給繞暈了,我們還是先看圖說話吧。

\

他們之間的的關系到底有多深呢,且聽我一一道來。最上層ViewGrou抽象下來的Adapter,擁有很多子類,Spinner的具體實現,跟蹤源代碼發現內部有實例化出一個ListPopuWindow、DialogPopup(根據不同的mode選擇不同的實例,本質區別一個是popuwindow一個是AlertDialog),而ListPZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcHVXaW5kb3fA4MjDztK3os/WwcvV4sO0uPa2q873RHJvcERvd25MaXN0VmlldyC1xMq1wP2jqEFsZXJ0RGlhbG9nzazR+bX308PBy2dldExpdFZpZXe3vbeoo6k8L3A+DQo8cHJlIGNsYXNzPQ=="brush:java;"> private static class DropDownListView extends ListView { }

由此可以知道每個ListPopuWindow裡面有一個LIstView,Spinner彈出來的其實就是ListView綁定適配器,而Spinner內部定義了一個DropDownAdapter,ListView綁定Adapter,最後調用各自mode對應的popu.show就可以了。那麼問題來了,Spinner在很麼時候彈出ListPopuWindow?帶著這個問題繼續跟蹤Spinner源碼

ViewGroup繼承自View,所以可以共享父類方法performClick,點擊時會調用該方法,自然Spinner也不例外,具體調用代碼塊如下(當然還有其他地方有觸發,這裡暫不深入理解了)

    @Override
    public boolean performClick() {
        boolean handled = super.performClick();

        if (!handled) {
            handled = true;

            if (!mPopup.isShowing()) {
                mPopup.show(getTextDirection(), getTextAlignment());
            }
        }

        return handled;
    }

用過的人都知道Spinner的Item預定義樣式有點丑陋,主要是AbsSpinner搞鬼,下面是預定義的載入代碼塊(修改Spinner樣式可以參考adapter這裡的調用)

  public AbsSpinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initAbsSpinner();

        final TypedArray a = context.obtainStyledAttributes(
                attrs, R.styleable.AbsSpinner, defStyleAttr, defStyleRes);

        final CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries);
        if (entries != null) {
            final ArrayAdapter adapter = new ArrayAdapter(
                    context, R.layout.simple_spinner_item, entries);
            adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
            setAdapter(adapter);
        }

        a.recycle();
    }

看完Spinner有了個大概的認知,再看AutoCompleteTextView(他的子類同理略過了),內部同樣實例了ListPopuWindow,添加了一個EditText輸入內容的監聽

   addTextChangedListener(new MyWatcher());

如果你對這個方法不陌生應該秒懂了吧,根據輸入內容,當輸入內容有變化立即執行過濾匹配適配器,這裡過濾具體實現暫不涉及。

CheckedTextView

在之前我寫過一篇關於ListView的單選和多選相關的分析的博客http://blog.csdn.net/analyzesystem/article/details/51319841,裡面有提到一個非常重要的接口Checkable,這裡就不多說廢話了,同時提供一個開源庫關於CheckedTextView相關的擴展庫(別太當真,看看就好,擴展視野)
https://github.com/akbarsha03/Custom_CheckedTextView

Chronometer

這是一個擴展子TextView的計時器控件,然而我不得不吐槽,官方提供的很多原生控件都不咋樣,與開源項目同類型的開源控件沒法比

小結

收獲了兩點:

1.在onAttachedToWindow和onDetachedFromWindow方法注冊廣播和取消注冊,接收到廣播,來做一些回調或者更新UI
2.了解了Spinner AutoCompleteTextView ListView等相關類的相關實現。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved