跳到主要內容

[Android]自定義View的概要與Source Code資源

Android Develpers官網提供的範例:

Creating a View Class

http://developer.android.com/training/custom-views/create-view.html
Sample Code URL:
http://developer.android.com/shareables/training/CustomView.zip

自定義一個View的方法:
步驟一:
    開一Java檔extends
        (1)最原生的View
        (2)ViewGroup
        --------Layout類--------
        (3)LinearLayout
        (4)FrameLayout
        --------元件類--------
        (5)Button
   ...

步驟二:
    在res\values\attrs.xml定義屬性
    <resources>
    <declare-styleable name="PieChart">     <!--需與Java檔的ClassName相同 -->
        <attr name="autoCenterPointerInSlice" format="boolean"/>
        <attr name="highlightStrength" format="float"/>
        <attr name="labelColor" format="color"/>
        <attr name="labelHeight" format="dimension"/>
        <attr name="labelPosition" format="enum">
            <enum name="left" value="0"/>
            <enum name="right" value="1"/>
        </attr>
        <attr name="labelWidth" format="dimension"/>
        <attr name="labelY" format="dimension"/>
        <attr name="pieRotation" format="integer"/>
        <attr name="pointerRadius" format="dimension"/>
        <attr name="showText" format="boolean"/>
    </declare-styleable>
</resources>

還有這些屬性可以使用:

        <!-- Identifier for the child that represents the panel's handle. -->
        <attr name="handle" format="reference" />

       <!-- Defines opened handle (drawable/color). -->
        <attr name="openedHandle" format="reference|color" />

        <attr name="transitionTextColorDown" format="color" />

         <attr name="weight" format="fraction" />


步驟三:
    提供2種建構子:
    //Create View object from your JAVA code.
    public PieChart(Context context) {
        super(context);
        init();
    }

    //Call by the layout engine.
    public PieChart(Context context, AttributeSet attrs) {
        super(context, attrs);
        //Get the Attribute from XML layout.
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.PieChart,
                0, 0
        );

        try {
            // Retrieve the values from the TypedArray and store into
            // fields of this class.
            //
            // The R.styleable.PieChart_* constants represent the index for
            // each custom attribute in the R.styleable.PieChart array.
            mShowText = a.getBoolean(R.styleable.PieChart_showText, false);
            mTextY = a.getDimension(R.styleable.PieChart_labelY, 0.0f);
            mTextWidth = a.getDimension(R.styleable.PieChart_labelWidth, 0.0f);
            mTextHeight = a.getDimension(R.styleable.PieChart_labelHeight, 0.0f);
            mTextPos = a.getInteger(R.styleable.PieChart_labelPosition, 0);
            mTextColor = a.getColor(R.styleable.PieChart_labelColor, 0xff000000);
            mHighlightStrength = a.getFloat(R.styleable.PieChart_highlightStrength, 1.0f);
            mPieRotation = a.getInt(R.styleable.PieChart_pieRotation, 0);
            mPointerRadius = a.getDimension(R.styleable.PieChart_pointerRadius, 2.0f);
            mAutoCenterInSlice = a.getBoolean(R.styleable.PieChart_autoCenterPointerInSlice, false);
        } finally {
            // release the TypedArray so that it can be reused.
            a.recycle();
        }

        init();
    }

    步驟四:
    系統在開始onDraw()前,會多次呼叫onMeasure()去跟Layout問現在要畫的範圍是多大
    //
    // Measurement functions. This example uses a simple heuristic: it assumes that
    // the pie chart should be at least as wide as its label.
    //
    @Override
    protected int getSuggestedMinimumWidth() {
        return (int) mTextWidth * 2;
    }

    @Override
    protected int getSuggestedMinimumHeight() {
        return (int) mTextWidth;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Try for a width based on our minimum
        int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();

        int w = Math.max(minw, MeasureSpec.getSize(widthMeasureSpec));

        // Whatever the width ends up being, ask for a height that would let the pie
        // get as big as it can
        int minh = (w - (int) mTextWidth) + getPaddingBottom() + getPaddingTop();
        int h = Math.min(MeasureSpec.getSize(heightMeasureSpec), minh);

        setMeasuredDimension(w, h);
    }

   相關方法:
    heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (parent.getHeight() * mWeight), MeasureSpec.EXACTLY);

    int w = Math.max(minw, MeasureSpec.getSize(widthMeasureSpec));

    int specMode = MeasureSpec.getMode(measureSpec);
    if (specMode == MeasureSpec.EXACTLY) ....

    一開始系統傳進來的引數measureSpec是從main.xml裡抓過來的
    在MeasureSpec.getMode()裡會抓到的尺寸模式,有以下3種
 Mode
 Value
 備註
main.xml裡相對應的設定
AT_MOST
 -2147483648
 子視圖可自行調整尺寸大小
android:layout_width或height 設為"wrap_content"時
EXACTLY     
 1073741824
 父Layout已經很明確的定義該子視圖的大小
android:layout_width或height有自訂大小或為"fill_parent"時
UNSPECIFIED
 0
 父Layout未指定大小,子視圖可自行調整。


    步驟五:
    幾次的onMeasure()呼叫完後,(如果是繼承自View)就跑去呼叫onDraw()開始繪圖了。
    若是繼承自其他者,請參考以下:
    Here's a summary of some of the other standard methods that the framework calls on views:
CategoryMethodsDescription
CreationConstructorsThere is a form of the constructor that are called when the view is created from code and a form that is called when the view is inflated from a layout file. The second form should parse and apply any attributes defined in the layout file.
onFinishInflate()Called after a view and all of its children has been inflated from XML.
LayoutonMeasure(int, int)Called to determine the size requirements for this view and all of its children.
onLayout(boolean, int, int, int, int)Called when this view should assign a size and position to all of its children.
onSizeChanged(int, int, int, int)Called when the size of this view has changed.
DrawingonDraw(Canvas)Called when the view should render its content.
Event processingonKeyDown(int, KeyEvent)Called when a new key event occurs.
onKeyUp(int, KeyEvent)Called when a key up event occurs.
onTrackballEvent(MotionEvent)Called when a trackball motion event occurs.
onTouchEvent(MotionEvent)Called when a touch screen motion event occurs.
FocusonFocusChanged(boolean, int, Rect)Called when the view gains or loses focus.
onWindowFocusChanged(boolean)Called when the window containing the view gains or loses focus.
AttachingonAttachedToWindow()Called when the view is attached to a window.
onDetachedFromWindow()Called when the view is detached from its window.
onWindowVisibilityChanged(int)Called when the visibility of the window containing the view has changed.

總結來說︰
1.在res/values/新增一個自訂的attrs.xml2.在main.xml裡使用他們3.繼承View,並在(1)建構式 裡宣告初始值(2)在onMeasure()裡交待清楚這個自創的View應該有多大(3)在onDraw()裡開始繪圖

留言

這個網誌中的熱門文章

[Qt][Embedded][PXA270]
Porting Qt 4.8.6 for Creator XScale PXA270

這篇文章介紹這學期我在嵌入式作業系統課程,使用Creator XScale PXA270板子的一些學習筆記與製作final project的一些過程,歡迎各位多多指教~ 背景介紹 Creator XScale PXA270開發版是一塊由 新華電腦(microtime) 公司出品的 模組化XScale/ARM/SoC/FPGA/DSP嵌入式行動通訊發展平台 ,在此課程與final project主要使用的是"Create XScale‐PXA270 子板"與"MTLCD‐0708048 LCD Module",在Create XScale‐PXA270子板上的為Intel(現在已出售給Marvell)的 Xscale系列 PXA270 處理器,基於ARMv5TE架構指令集,在旁附有SDRAM Memory 64MB、Flash Memory 32MB、SD Card Connectors、RJ45 10/100 Base‐T Ethernet Interface、USB 1.1 Device/Host Port各一、AC97 Audio Codec(Line_in、Mic_in、Headphone)、ADC Interface*4、PWM Interface、CMOS Camera Interface、TFT-LCD Interface、GPIO Interface...等;在軟體功能部分,由新華科技提供了GNU GCC cross compiler toolchain(arm-unknown-linux-gnu-gcc 4.0.2)、Uboot 1.1.5、Linux Kernel 2.6.15.3與patch(提供支援子板上的Ethernet、USB Host、TFT‐LCD(Frame buffer、Touch Screen)、AC97‐Codec...等與母板LED、7‐Seg LED、Key Pad...等的device driver)、rootfs,相關的實驗環境設定可以參考 User Guide 。 看到以上這麼多的軟硬體介面,別以為這板子有多強,其實這是 2006 年 ASUS P535 手機使用的規格了,不禁讓人感嘆科技進步之快阿~ 在此附上開發版本尊 Qt 是自由且開放原始碼的跨平台C...

Run Android VTS with Android R emulator through WSL

Background Android VTS The Android Vendor Test Suite (VTS) provides extensive new functionality for Android testing and promotes a test-driven development process. Android R emulator Run the latest Android R image from Google CI build artifacts WSL WSL is a collection of components that enables native Linux ELF64 binaries to run on Windows . It contains both user mode and kernel mode components. It is primarily comprised of: User mode session manager service that handles the Linux instance life cycle Pico provider drivers (lxss.sys, lxcore.sys) that emulate a Linux kernel by translating Linux syscalls Pico processes that host the unmodified user mode Linux (e.g. /bin/bash) It is the space between the user mode Linux binaries and the Windows kernel components where the magic happens. By placing unmodified Linux binaries in Pico processes we enable Linux system calls to be directed into the Windows kernel. The lxss.sys and lxcore.sys drivers translate the Linux s...

[Arduino]Inside Arduino: Andes Andino M1

這篇文章記錄了最近探索Arduino與 台灣晶心科技Andes出的Andino M1('Andino'沒打錯!!他真的叫這名字)相容Arduino的IoT板子 的一些hacking與紀錄,歡迎各位多多指教~ 先來看看本尊 是的就是它!!小小一片 吐槽一下,在下圖看到橘框處竟然看到ARM Cortex-M3,不過在這邊這顆ARM似乎只拿來處理介面轉換,不然就都用這顆ARM應該效能更好? XDD 下載與安裝Arduino IDE 請到官網下載Arduino IDE https://www.arduino.cc/en/Main/Software?setlang=en 如果是使用Andes Andino M1,請務必下載Windows平台的 因為目前board support package只支援windows版... Arduino Board Manger 下載安裝好之後,接下來是加入Andes Andino M1的board support到Arduino 這邊有一個很重要的雷點!!!就是 Editor language務必要設為English ( 紅框處 ,預設使用Windows系統預設語言),否則在開啟Board Manger時會出現java.lang.RuntimeException: java.lang.IllegalArgumentException: Unmatched braces in the pattern.的錯誤訊息 在Additional Board Manger URLs中,輸入(橘框處): http://knect.me/andino/M1/package_Andino_knectme_index.json 然後按OK,到board manger按instasll安裝(點紅框處會出現按鈕): 安裝成功後,會看到有Andino M1可選(紫框處) 關於package_Andino_knectme_index.json的原理,我們可以看到在這個json檔案內,定義了platform與tools的資訊,Arduino會在開啟Board Manger時,去下載讀取所有使用者額外新增的json網址,然後在按下安裝時去下載於該檔內定義的toolchain,這...