前言
做程序開發(fā),基礎(chǔ)很重要延都。同樣是擰螺絲人家擰出來的可以經(jīng)久不壞雷猪,你擰出來的遇到點(diǎn)風(fēng)浪就開始顫抖,可見基本功的重要性晰房。此系列求摇,專門收錄一些看似基礎(chǔ),但是沒那么簡單的小細(xì)節(jié)殊者,同時(shí)提供權(quán)威解決方案与境。喜歡的同志們點(diǎn)個(gè)贊就是對(duì)我最大的鼓勵(lì)!先行謝過猖吴!
網(wǎng)上可能有一些其他文章摔刁,提供了解決方案,但是要么就是沒有提供可運(yùn)行demo
海蔽,要么就是demo不夠純粹
共屈,讓人探索起來受到其他代碼因素的影響,無法專注于當(dāng)前這個(gè)知識(shí)點(diǎn)(比如准潭,我只是想了解Activity
的生命周期趁俊,你把生命周期探究的過程混入到一個(gè)很復(fù)雜的大雜燴Demo
中,讓人一眼就沒有了閱讀Demo代碼
的欲望)刑然,所以我覺得有必要做一個(gè)專題,用最純粹
的方式展示一個(gè)坑
的解決方案.
干貨
如下圖所示暇务,如果 你有一個(gè)自定義的TestView代碼如下:只是簡單的繪制一個(gè)文字
package study.hank.com.draw001.custom;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import study.hank.com.draw001.R;
import study.hank.com.draw001.Utils;
public class TestView extends View {
public TestView(Context context) {
this(context, null);
}
public TestView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public TestView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(getResources().getColor(R.color.aoyun_4));
paint.setStyle(Paint.Style.FILL);
paint.setTextAlign(Paint.Align.LEFT);
paint.setTextSize(Utils.dp2px(50));
canvas.drawText("測試文字", 100, 200, paint);
}
}
然而你不知道出于什么原因泼掠,將它放到了ScrollView
里面:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorF">
<study.hank.com.draw001.custom.TestView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</ScrollView>
然后你運(yùn)行起來,看到的:是這樣的
哎呀垦细?什么都沒有择镇?是的,什么都沒有括改,但是如果我在 TextView里面加上onMeasure腻豌,變成下面這樣
package study.hank.com.draw001.custom;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import study.hank.com.draw001.R;
import study.hank.com.draw001.Utils;
public class TestView extends View {
public TestView(Context context) {
this(context, null);
}
public TestView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public TestView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//比之前多出這個(gè)方法重寫
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode == MeasureSpec.UNSPECIFIED) {
setMeasuredDimension(widthSize, widthSize * 2);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(getResources().getColor(R.color.aoyun_4));
paint.setStyle(Paint.Style.FILL);
paint.setTextAlign(Paint.Align.LEFT);
paint.setTextSize(Utils.dp2px(50));
canvas.drawText("測試文字", 100, 200, paint);
}
}
再運(yùn)行:就有文字顯示了
原理
一般來說,很少有人會(huì)把自定義View放到ScrollView里面,但是如果發(fā)生了這種問題吝梅,我們應(yīng)該要知道往哪個(gè)方向思考虱疏,所以探究一下原理,為什么我們自己對(duì)
UNSPECIFIED
進(jìn)行處理之后苏携,就能顯示了呢做瞪?
進(jìn)入ScrollView
的源碼, 找到onMeasure
方法:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!mFillViewport) {
return;
}
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode == MeasureSpec.UNSPECIFIED) {
return;
}
...省略一大段
}
}
我們可以看到ScrollView
對(duì)高的 UNSPECIFIED
并未做處理右冻,直接return
了.
直接導(dǎo)致我們TestView
(如果TestView自己也不作處理的話
) 默認(rèn)的測量方式得出的高度就是 初始值 0
装蓬,所以你什么都看不到.
所以,當(dāng)我們自己給TestView
重寫onMeasure
之后纱扭,
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode == MeasureSpec.UNSPECIFIED) {
setMeasuredDimension(widthSize, 500);
Log.d("onMeasureTag", "第" + c++ + "次測量 - 之后的寬是:" +
getMeasuredWidth() + " / 高是:" + getMeasuredHeight());
}
}
就能看到文字了(為了表示TestView的范圍牍帚,我加了個(gè)橙色背景)
這是此時(shí)的日志:
至于更深層次的原因,比如乳蛾,為何ScrollView要對(duì)UNSPECIED不作處理暗赶。那就不得而知了,也沒必要知道的這么清楚屡久,誰知道谷歌大佬的想法呢···就這樣了忆首,歐了!