1. 程式人生 > >android學習5#--自定義View之座標系統

android學習5#--自定義View之座標系統

近期在學習android過程中,看到有人在伯樂在線上分享如何開發自定義View的一系列文章。我覺得對於初學者,很有必要掌握它,因為今後很多時候系統自帶的元件不足以滿足我們的功能需求,那麼我們就要根據需求來定義一個能滿足我們需求的View元件。
但是我並不會按照伯樂線上的系列文章來學習,就記錄我是怎麼學的,今天來講講我對座標的理解。參考:伯樂線上[安卓自定義View基礎:座標系]

Android移動裝置的座標一般定義螢幕左上角為座標原點,與我們平時理解的座標系統不一樣的是:平時所理解的座標Y軸向上增大,而Android移動裝置是向下增長的

獨立畫素(dp)和畫素(px)

在講View的座標系統前首先需要掌握android中的dp與px之間的關係。
在開發過程中,肯定要給元件佈局定位的,而android有兩個常用計量單位獨立畫素(dp)和畫素(px)。
px:因為pixel的縮寫,它表示一個實實在在的物理畫素。他不會隨裝置的解析度改變而改變。
dp/dip:英文device independent pixels的簡稱,翻譯成中文叫裝置獨立畫素,為什麼要有dp出來呢,因為我們的移動裝置解析度是有多種的,那麼為了讓應用中的view元件能夠自適應各種解析度的顯示裝置,於是乎就產生了dp。提高了程式的可移植性,因為android最終會將dp轉成具體裝置的畫素數。最終是如何轉換成px 的呢?先看下面的公式:

    public static int dip2px(Context context, float dipValue){
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int)(dipValue * scale + 0.5f);
    }

上面的公式中出現了一個density,呵呵,又是一個新東西。不怕,找度娘,density表示每英寸有多少個顯示點。但是我寫了一個應用列印這個值為2.625,而我的螢幕實際density值為420。咦,為何不一樣啊,這個問題困擾了我不少時間,估計大家也暈了,先不管,我們一個一個來,先來看看android是如何定義這裡的density,如下:

    /**
     * The logical density of the display.  This is a scaling factor for the
     * Density Independent Pixel unit, where one DIP is one pixel on an
     * approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen), 
     * providing the baseline of the system's display. Thus on a 160
dpi screen * this density value will be 1; on a 120 dpi screen it would be .75; etc. * * <p>This value does not exactly follow the real screen size (as given by * {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of * the overall UI in steps based on gross changes in the display dpi. For * example, a 240x320 screen will have a density of 1 even if its width is * 1.8", 1.3", etc. However, if the screen resolution is increased to * 320x480 but the screen size remained 1.5"x2" then the density would be * increased (probably to 1.5). * * @see #DENSITY_DEFAULT */ public float density;

簡單翻譯下,可以理解為density的數值是dpi/160算出來的,因為標準是240*320畫在1.5*2平方inch上。那麼像每平方英寸有240*320/(1.5*2)=25600點,也就是一平方英尺的畫素點為25600,所以dpi取為它的平方根160;如果dpi是420,那麼density為420/160=2.625。由此可以看出來前面百度搜到的density應該跟dpi是同一個概念,我看有些文件上把DensityDpi來表示每英寸有多少個顯示點。這樣概念就不會搞模糊了。

通過例項來理解View的座標

瞭解了dp、px的關係,接下來就可以通過例項來理解view的座標是怎麼設計的。
例項佈局xml部分原始碼:

    <FrameLayout
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginLeft="100dp"
        android:layout_marginTop="100dp"
        android:nestedScrollingEnabled="true"
        android:background="#acb7ac"
        android:id="@+id/view1">

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="10dp"
            android:id="@+id/view2"
            android:background="#687fb3"/>
    </FrameLayout>

畫了兩個view,通過下面四個函式獲取他們的座標:

  getTop();       //獲取子View左上角距父View頂部的距離
  getLeft();      //獲取子View左上角距父View左側的距離
  getBottom();    //獲取子View右下角距父View頂部的距離
  getRight();     //獲取子View右下角距父View左側的距離

需要注意的是這裡面獲取到的距離都是畫素為單位。

具體程式碼如下:

public class MainActivity extends AppCompatActivity {

    protected final String LOG_TAG = "Coordinate";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);

        View view1 = findViewById(R.id.view1);
        View view2 = findViewById(R.id.view2);

        Log.d(LOG_TAG, "onWindowFocusChanged.density: "+this.getResources().getDisplayMetrics().density);

        Log.d(LOG_TAG, "view1.left:" + view1.getLeft());
        Log.d(LOG_TAG, "view1.right:" + view1.getRight());
        Log.d(LOG_TAG, "view1.height:" + view1.getHeight());
        Log.d(LOG_TAG, "view1.width:" + view1.getWidth());
        Log.d(LOG_TAG, "view1.top:" + view1.getTop());
        Log.d(LOG_TAG, "view1.bottom:" + view1.getBottom());

        Log.d(LOG_TAG, "view2.left:" + view2.getLeft());
        Log.d(LOG_TAG, "view2.right:" + view2.getRight());
        Log.d(LOG_TAG, "view2.height:" + view2.getHeight());
        Log.d(LOG_TAG, "view2.width:" + view2.getWidth());
        Log.d(LOG_TAG, "view2.top:" + view2.getTop());
        Log.d(LOG_TAG, "view2.bottom:" + view2.getBottom());
    }
}

上面的code需要注意下,就是coCreate()方法中呼叫View的getTop()等方法時,是無法獲取到正確值的,只會返回0,因為View的顯示必須經歷Measure(測量)、Layout(佈局)和Draw(繪製)過程。而在Measure與Layout過程完成後,View的width、height、top、left等屬性才被正確賦值,此時我們才能獲取到正確的值,這幾個過程都晚於onCreate執行。因此我放在重新onWindowFocusChanged()方法裡面。當然還有其它方法,參考http://www.2cto.com/kf/201504/395362.html

執行結果:
示意圖:
這裡寫圖片描述
Log列印如下:

06-15 04:40:39.390 19910-19910/com.uudou.study.coordinate D/Coordinate: view1.left:263
06-15 04:40:39.390 19910-19910/com.uudou.study.coordinate D/Coordinate: view1.right:526
06-15 04:40:39.390 19910-19910/com.uudou.study.coordinate D/Coordinate: view1.height:263
06-15 04:40:39.390 19910-19910/com.uudou.study.coordinate D/Coordinate: view1.width:263
06-15 04:40:39.390 19910-19910/com.uudou.study.coordinate D/Coordinate: view1.top:263
06-15 04:40:39.390 19910-19910/com.uudou.study.coordinate D/Coordinate: view1.bottom:526
06-15 04:40:39.390 19910-19910/com.uudou.study.coordinate D/Coordinate: view2.left:26
06-15 04:40:39.390 19910-19910/com.uudou.study.coordinate D/Coordinate: view2.right:157
06-15 04:40:39.390 19910-19910/com.uudou.study.coordinate D/Coordinate: view2.height:131
06-15 04:40:39.390 19910-19910/com.uudou.study.coordinate D/Coordinate: view2.width:131
06-15 04:40:39.390 19910-19910/com.uudou.study.coordinate D/Coordinate: view2.top:26
06-15 04:40:39.390 19910-19910/com.uudou.study.coordinate D/Coordinate: view2.bottom:157

從執行效果圖跟log來分析,發現view的座標都是相對於父控制元件而言的,這裡盜用伯樂線上的一張圖如下:
這裡寫圖片描述

相關推薦

android學習5#--定義View座標系統

近期在學習android過程中,看到有人在伯樂在線上分享如何開發自定義View的一系列文章。我覺得對於初學者,很有必要掌握它,因為今後很多時候系統自帶的元件不足以滿足我們的功能需求,那麼我們就要根據需求來定義一個能滿足我們需求的View元件。 但是我並不會按照

Android進階——定義View擴充套件系統控制元件的另一種思路實現漸變文字動畫的TextView

引言 前面幾篇文章 繼承或組合系統現有控制元件實現新控制元件,擴充套件新功能都是在對應的構造方法中去擴充套件的,但千萬不要把思路侷限於只能在構造方法中去擴充套件,這篇就簡單地分享另一種思路,通過重寫對應的週期方法實現擴充套件。 一、View中幾種重

Android進階——定義View組合系統控制元件實現水珠形狀的ItemView

引言 相信大家在專案開發的過程中一定會有不少需要在上方顯示一張圖片,而在其下方顯示提示標題的效果,作為一個介面的功能按鈕或者單純作為一個列表的item項,尤其是當這個item還需要顯示一些動畫效果時候,此時更應該當成一個整體,否則動畫效果就會需要額外的調整,否

Android學習—簡單定義View(一)

最近手上不忙所以回顧了一下自己今年來所接觸和學習的東西,突然覺得寫部落格真是一個很好的方式,希望自己 可以堅持下去。 自定義View的流程 建立自定義類繼承View,並重寫構造方法,構造方法總共有四種,我們暫時只需要繼承前兩種 public CircleVi

Android繪圖:定義View——矩形進度條、圓環進度條、填充型進度條、時鐘

主函式 這幾種進度條的主函式都是類似的,所以下面我只給出了一個填充型進度條的主函式,其他幾個主函式只是在這基礎上改動一下按鈕id(即與各自佈局裡面的id相同即可),還有改動一下相對應的類即可。 public class MainActivity

Android進階——定義View繼承TextView巧用DrawableLeft實現自己的CheckableTextView

引言 Android自帶的許多控制元件已經十分強大,甚至很多功能都已經有現成的控制元件去使用了,不過介面效果是肯定會打折扣的,幸好android控制元件自身的擴充套件性十分優秀,很多時候我們只需要簡單繼承下現有控制元件擴充套件些許功能就能得到一個全新的控制元件

Android進階——定義ViewView的繪製流程及實現onMeasure完全攻略

引言 Android實際專案開發中,自定義View不可或缺,而作為自定義View的一種重要實現方式——繼承View重繪尤其重要,前面很多文章基本總結了繼承View的基本流程:自定義屬性和繼承View重寫onDraw方法——>實現構造方法並完成相關初始化操

Android定義View分貝儀

一、說明        最近在整理自定義View方面的知識,偶爾看到meizu工具箱的分貝儀效果,感覺它的實效效果還挺好的,遂想自己模擬實現練練手,廢話不多說,直接開擼。 二、效果圖 首先看一下效果圖: 看效果還挺炫酷

Android定義ViewCanvas

https://www.jianshu.com/p/fb18c28d6627 用繼承View的方式來自定義View,我們就需要重寫onDraw方法,也就是得咱自己來畫圖了。畫圖就得用到畫筆和畫布,也就是Paint和Canvas。我們來了解下Canvas。 Canvas Canvas我們可

Android 定義ViewCanvas詳解

自定義View的相關文章: Android 實現一個簡單的自定義View Android 自定義View步驟 Android Paint詳解 Android 自定義View之Canvas相關方法說明 Android 自定義View例項之 “京東跑”

Android : 定義View流式佈局

寫了一個很簡單的佈局 這是周圍圓框的drawable <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android">

android定義View仿通訊錄側邊欄滑動,實現A-Z字母檢索

我們的手機通訊錄一般都有這樣的效果,如下圖: OK,這種效果大家都見得多了,基本上所有的android手機通訊錄都有這樣的效果。那我們今天就來看看這個效果該怎麼實現。 一.概述 1.頁面功能分析 整體上來說,左邊是一個ListView,右邊是一個自定義View,但

Android定義ViewgetTextBounds()

在Android自定義View的過程中一定會用到Paint,而paint屬性中有一個方法getTextBounds(String text,int start,int end,Rext bounds),它的中文解釋是:返回一個包含中文的矩形邊界,位置為(start,end) 英文解釋:Retur

Android定義View定義屬性

在Android開發中經常會用到自定義View的情況,而在自定義View時,自定義屬性是必須用到的。 1、新建一個自定義View如CustomView 它的自定義屬性主要是通過declare-styleable標籤為其配置自定義屬性。具體做法是:在res/values/目錄下增加一個reso

Android -- 定義viewStepView

先看看實現的效果: 2,首先我們來看看我們常規的自定義view的基礎步驟吧         1,繼承View,重寫構造方法 2,自定義屬性 3,重寫onMeasure()測量控制元件高度 4,重寫onDra

Android 定義View 可隨意拖動的View

因為趕專案本人停更兩個月 從今天開始又可以更新了 今天說一下這個可隨意拖動的view 簡單說一下這個view效果 和 發展 一開始這種效果是使用在網頁端的特別是購物類 例如某寶 某東 購物車和客服視窗 都有使用這個懸浮可拖動的設計效果 後來才發展到的移動端 還有

Android 定義View咖啡動畫

文章目錄效果畫杯子畫杯墊畫煙霧 效果 大概思路 自定義view,直接繼承view 複寫onSizeChanged()方法,在此計算杯墊,杯子,煙霧效果的path 在onDraw()方法中,描繪杯墊,杯子 處理煙霧動畫效果 畫杯子 這裡需要畫兩部分內容,第

Android 定義View下雨動畫

文章目錄效果思路畫雲畫雨滴優化 效果 開始前先做個熱身( ˘•灬•˘ ) 自己實現比較容易,但是到了要出部落格整理思路,總結要點的時候就撓頭,不知雲所以,所以最簡單的還是 如果對安卓UI有興趣的朋友可以加我好友互相探討, 思路 思路比較簡單,整個view無

android定義View定義EditText(新增刪除功能)

           忙忙碌碌20天,新的專案終於接近尾聲了。今天公司召集幾個使用者體驗師和美工一起吐糟這20天做的這個新產品,對於產品提出了很多建議,這幾天就改介面了。在這個專案中大量的使用了EditText元件,並且添加了刪除功能。這裡面都是用RelativeLayou

android定義view畫圓隨著手指移動

public class MyView extends View { private Paint mFanPaint,mTextPaint;//扇形畫筆和文字畫筆 public float AxisX=100; public float AxisY=100; public MyView(