Android-獲取View寬高的時機(jī)

前言:

最近遇到一個bug,問題描述是這樣的:啟動頁需要放置一張廣告圖药薯,要使這張圖在不變形的情況下(等比例縮放)绑洛,寬度要占滿屏幕寬,于是手動計算并設(shè)置ImageView需要的縮放比例來對圖片進(jìn)行縮放童本。該方法觸發(fā)的時機(jī)引發(fā)了一些問題真屯。

private void scaleView(ImageView iv) {
        if (iv.getDrawable() == null) {
            return;
        }
        Matrix matrix = iv.getImageMatrix();
        float scaleWidth = (float) iv.getWidth() / (float) iv.getDrawable().getIntrinsicWidth();
        float scaleHeight = (float) iv.getHeight() / (float) iv.getDrawable().getIntrinsicHeight();
        float scaleFactor = scaleWidth > scaleHeight ? scaleWidth : scaleHeight;
        matrix.setScale(scaleFactor, scaleFactor, 0.0F, 0.0F);
        if (BigDecimal.valueOf((double) scaleFactor).compareTo(BigDecimal.valueOf((double) scaleHeight)) == 0) {
            float translateX = ((float) iv.getDrawable().getIntrinsicWidth() * scaleFactor - (float) iv.getWidth()) / 2.0F;
            matrix.postTranslate(-translateX, 0.0F);
        }
        iv.setImageMatrix(matrix);
    }

問題在于:

xml布局中使用了match_parent來定義ImageView大小,然而我在Fragment的onViewCreated方法中來調(diào)用該方法(當(dāng)然在Activity的onCreate方法中調(diào)用也是一樣)穷娱,從上面代碼可以發(fā)現(xiàn) iv.getWidth()/iv.getHeight()需要獲取ImageView的width和height來計算比例绑蔫,而此時并沒有進(jìn)行Layout,所以iv.getWidth()/iv.getHeight()的返回值是0泵额,導(dǎo)致該圖片最終不可見或者縮放操作無效配深。

解決思路:

問題的關(guān)鍵在于修改觸發(fā)這個函數(shù)的時機(jī),好的時機(jī)是在View的onLayout函數(shù)結(jié)束之后用戶可見之前嫁盲,因為此時實際高寬已經(jīng)確定(提醒一下測量高寬MeasureWidth/MeasureHeight不一定等于實際高寬Width/Height)

解決方案:

總結(jié)了三種常見的解決方案篓叶,如下:

1.手動調(diào)用view的measure方法(不太建議):

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final MyImageView myImageView = (MyImageView) findViewById(R.id.imageview);
        int w = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
        int h = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
        myImageView.measure(w, h);
        Log.d("===MainActivity", "onCreate執(zhí)行完畢..myImageView " +
                "height:" + myImageView.getMeasuredHeight() + "  ,width:" + myImageView.getMeasuredWidth());
    }

手動調(diào)用之后就確保可以獲取到MeasuredHeight了羞秤,但MeasuredHeight不一定等于Height缸托。

2.利用ViewTreeObserver注冊addOnPreDrawListener監(jiān)聽

ViewTreeObserver vto = myImageView.getViewTreeObserver();
        vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            public boolean onPreDraw() {
                int height = myImageView.getMeasuredHeight();
                int width = myImageView.getMeasuredWidth();
                Log.d("===PreDrawListener", "PreDrawListener..myImageView " +
                        "height:" + height + "  ,width:" + width);
                myImageView.getViewTreeObserver().removeOnPreDrawListener(this);
                return true;
            }
        });

ViewTreeObserver,View事件的觀察者瘾蛋,可以用來監(jiān)聽視圖樹俐镐,會監(jiān)聽視圖樹發(fā)生全局變化時發(fā)出的通知。這里指的全局 事件包括而且不局限在以下幾個:整個視圖樹的布局變化哺哼,開始繪制視圖京革,觸摸模式改變等等。添加addOnPreDrawListener確保了Layout過程執(zhí)行幸斥,此時能獲取寬高匹摇,在獲取之后應(yīng)及時調(diào)用remove方法將監(jiān)聽移除

3.利用ViewTreeObserver注冊O(shè)nGlobalLayoutListener監(jiān)聽

ViewTreeObserver vto = myImageView.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                myImageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                Log.d("===OnGlobalLayout", "OnGlobalLayoutListener..myImageView " +
                        "height:" + myImageView.getHeight() + "  ,width:" + myImageView.getWidth());
            }
        });

跟方法2類似,只不過換了個監(jiān)聽甲葬,可以實現(xiàn)
**值得注意的是remove方法需要兼容一下sdk版本:

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                        mWelcomeImageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    } else {
                        mWelcomeImageView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    }

**

4.使用View.post(new Runnable)該方法比較巧妙廊勃,也是我比較喜歡的。

mWelcomeImageView.post(new Runnable() {
                @Override
                public void run() {
                    scaleView(mWelcomeImageView);
                    mWelcomeImageView.invalidate();
                }
            });

該方法將涉及獲取高寬的方法使用post方法加入到隊列中,而該方法的調(diào)用一定是在View被創(chuàng)建成功之后

注意點:在圖片最大高度確定時坡垫,若按屏幕寬度等比例縮放圖片梭灿,需要圖片高度超出控件高度才能實現(xiàn),此時需要添加一個scaleType:matrix屬性冰悠,如下:

<ImageView
            android:id="@+id/welcome"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginBottom="100dp"
            android:scaleType="matrix" />
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末堡妒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子溉卓,更是在濱河造成了極大的恐慌皮迟,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桑寨,死亡現(xiàn)場離奇詭異伏尼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)尉尾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門爆阶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沙咏,你說我怎么就攤上這事辨图。” “怎么了肢藐?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵徒役,是天一觀的道長。 經(jīng)常有香客問我窖壕,道長,這世上最難降的妖魔是什么杉女? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任瞻讽,我火速辦了婚禮,結(jié)果婚禮上熏挎,老公的妹妹穿的比我還像新娘速勇。我一直安慰自己,他們只是感情好坎拐,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布烦磁。 她就那樣靜靜地躺著,像睡著了一般哼勇。 火紅的嫁衣襯著肌膚如雪都伪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天积担,我揣著相機(jī)與錄音陨晶,去河邊找鬼。 笑死帝璧,一個胖子當(dāng)著我的面吹牛先誉,可吹牛的內(nèi)容都是我干的湿刽。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼褐耳,長吁一口氣:“原來是場噩夢啊……” “哼诈闺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起铃芦,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤雅镊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后杨帽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漓穿,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年注盈,在試婚紗的時候發(fā)現(xiàn)自己被綠了晃危。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡老客,死狀恐怖僚饭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胧砰,我是刑警寧澤鳍鸵,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站尉间,受9級特大地震影響偿乖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜哲嘲,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一贪薪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧眠副,春花似錦画切、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至娃弓,卻和暖如春典格,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背台丛。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工钝计, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓私恬,卻偏偏與公主長得像债沮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子本鸣,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容