Android OnMeasure詳解

Android OnMeasure是ViewGroup中用於確定視圖大小的方法,它掌握了視圖在屏幕上的高度和寬度,而這些信息又是布局和繪製所必需的。在這篇文章中,我將從以下幾個方面進行詳細闡述OnMeasure的用處與實現原理。

一、OnMeasure的作用

OnMeasure是Android布局中最為關鍵的方法之一,它在布局時確定視圖的大小。當ViewGroup被測量時,每個子視圖的OnMeasure方法都會被調用,ViewGroup就能在得到自己的即將使用的尺寸之後,調用子視圖的OnLayout方法,以達到正確繪製的效果。

OnMeasure方法實際上是兩個部分:測量模式和測量值。單獨一個測量模式是沒法確定測量大小(測量值)的。

MeasureSpec是Android中非常重要的一個類,它表示了一個ViewGroup上的子視圖的布局要求。MeasureSpec是由一個模式值和大小組成的,僅僅知道模式是沒有用的,需要同時知道大小。

MeasureSpec由高2位代表模式,低30位表示大小。模式定義如下:

  • UNSPECIFIED(不確定模式)–視圖想要多大就可以多大
  • EXACTLY(精確模式)–視圖必須恰好fill_parent,match_parent(-1dp)或者一個確定的大小
  • AT_MOST(至多模式)–視圖可以是任何大小,但不能比fill_parent還要大

二、OnMeasure的實現方式

在編寫自定義視圖時,我們可以需要重寫其OnMeasure方法。下面是一個自定義視圖的例子:

public class MyView extends View {

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int desiredWidth = 100;
        int desiredHeight = 100;

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width;
        int height;

        //確定寬度大小
        if (widthMode == MeasureSpec.EXACTLY) {
            //父視圖要求一個具體的大小
            width = widthSize;
        } else if (widthMode == MeasureSpec.AT_MOST) {
            //調整為目標尺寸或更小
            width = Math.min(desiredWidth, widthSize);
        } else {
            //unspecified
            width = desiredWidth;
        }

        //確定高度大小
        if (heightMode == MeasureSpec.EXACTLY) {
            //父視圖要求一個具體的大小
            height = heightSize;
        } else if (heightMode == MeasureSpec.AT_MOST) {
            //調整為目標尺寸或更小
            height = Math.min(desiredHeight, heightSize);
        } else {
            //unspecified
            height = desiredHeight;
        }

        //重寫後,調用此方法讓ViewGroup知道子視圖的大小
        setMeasuredDimension(width, height);
    }
}

這個例子中的MyView是一個非常簡單的自定義View,它只是繪製了一些“虛假”內容,但是展示了如何實現OnMeasure方法。OnMeasure方法在這個例子中通過制定一個預期的大小和測量規則來獲取大小和規則,具體實現如下:

  • 從MeasureSpec中解析出測量模式(mode)和測量值(size)
  • 如果mode是EXACTLY,尺寸就是size。這可能是父視圖在布局時,為子視圖指定精確的大小。
  • 如果mode是AT_MOST,尺寸不能大於size。這可能是父視圖在布局時,應該根據子視圖的大小來調整。可以使用整個屏幕空間,但不能比其指定大小還要大。
  • 如果mode是UNSPECIFIED,這意味着視圖沿着父視圖方向想要多大就能有多大。這種情況不太常見。例子就省略了此情況。

三、OnMeasure的使用場景

在很多情況下,OnMeasure需要進行重載。

  • 自定義視圖的大小
  • 視圖內部的子視圖數目不固定
  • 視圖內部有嵌套的自定義視圖
  • 視圖的大小和位置是由其他組件決定的

在這些情況中,視圖根據其成為一個複雜或特定的類別而變得獨特。那麼我們就需要重寫OnMeasure方法,以實現自己期望的測量方式的視圖。下面的代碼中,將演示如何在一個具體情況中重載OnMeasure方法,具體實現如下:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        assert (widthMode == MeasureSpec.UNSPECIFIED
                || widthMode == MeasureSpec.AT_MOST);
        assert (heightMode == MeasureSpec.UNSPECIFIED
                || heightMode == MeasureSpec.AT_MOST);

        int desiredWidth = 200;
        int desiredHeight = 200;

        int width = desiredWidth;
        int height = desiredHeight;

        setMeasuredDimension(width, height);
    }

在這個例子中,我們獲取了ViewGroup的寬度和高度的測量模式,並計算出一個指定的大小,除此之外,我們也可以重寫此方法來根據狀態調整大小。

四、OnMeasure的注意事項

在重載OnMeasure方法時,需要注意以下幾點:

  • 對於自定義ViewGroup,必須調用子視圖的measure()方法來確定其大小
  • 嘗試最大限度的讓布局不受限制
  • 您可以根據需要以不同的方式調整視圖的大小,但必須要注意在大多數情況下,覆蓋View的onMeasure()不是一個好的設計模式
  • 考慮OnLayout的實現,正確定位是在OnLayout中處理的,而不是在OnMeasure中

五、總結

Android OnMeasure是實現自定義視圖重要的方法,實現時需要注意一些細節。它通過MeasureSpec抽象類來規定測量大小和模式,以及調整ViewGroup子元素的大小。

以上是關於OnMeasure的詳細介紹,希望讀者能夠了解布局視圖的最基本方法。完成這篇文章,你已經掌握了如何利用OnMeasure打造自己的自定義視圖,同時也學習了一些重要的注意事項。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/158021.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-11-19 00:38
下一篇 2024-11-19 00:38

相關推薦

  • Android ViewPager和ScrollView滑動衝突問題

    Android開發中,ViewPager和ScrollView是兩個常用的控件。但是當它們同時使用時,可能會發生滑動衝突的問題。本文將從多個方面介紹解決Android ViewPa…

    編程 2025-04-28
  • Android如何點擊其他區域收起軟鍵盤

    在Android應用中,當輸入框獲取焦點彈出軟鍵盤後,我們希望能夠點擊其他區域使軟鍵盤消失,以提升用戶體驗。本篇文章將說明如何實現這一功能。 一、獲取焦點並顯示軟鍵盤 在Andro…

    編程 2025-04-28
  • Android Studio HUD 實現指南

    本文將會以實例來詳細闡述如何在 Android Studio 中使用 HUD 功能實現菊花等待指示器的效果。 一、引入依賴庫 首先,我們需要在 build.gradle 文件中引入…

    編程 2025-04-27
  • Android和Vue3混合開發方案

    本文將介紹如何將Android和Vue3結合起來進行混合開發,以及其中的優勢和注意事項。 一、環境搭建 在進行混合開發之前,需要搭建好相應的開發環境。首先需要安裝 Android …

    編程 2025-04-27
  • Android Java Utils 可以如何提高你的開發效率

    Android Java Utils 是一款提供了一系列方便實用的工具類的 Java 庫,可以幫助開發者更加高效地進行 Android 開發,提高開發效率。本文將從以下幾個方面對 …

    編程 2025-04-27
  • Linux sync詳解

    一、sync概述 sync是Linux中一個非常重要的命令,它可以將文件系統緩存中的內容,強制寫入磁盤中。在執行sync之前,所有的文件系統更新將不會立即寫入磁盤,而是先緩存在內存…

    編程 2025-04-25
  • 神經網絡代碼詳解

    神經網絡作為一種人工智能技術,被廣泛應用於語音識別、圖像識別、自然語言處理等領域。而神經網絡的模型編寫,離不開代碼。本文將從多個方面詳細闡述神經網絡模型編寫的代碼技術。 一、神經網…

    編程 2025-04-25
  • Linux修改文件名命令詳解

    在Linux系統中,修改文件名是一個很常見的操作。Linux提供了多種方式來修改文件名,這篇文章將介紹Linux修改文件名的詳細操作。 一、mv命令 mv命令是Linux下的常用命…

    編程 2025-04-25
  • git config user.name的詳解

    一、為什麼要使用git config user.name? git是一個非常流行的分布式版本控制系統,很多程序員都會用到它。在使用git commit提交代碼時,需要記錄commi…

    編程 2025-04-25
  • nginx與apache應用開發詳解

    一、概述 nginx和apache都是常見的web服務器。nginx是一個高性能的反向代理web服務器,將負載均衡和緩存集成在了一起,可以動靜分離。apache是一個可擴展的web…

    編程 2025-04-25

發表回復

登錄後才能評論