안 드 로 이 드 사용자 정의 viewgroup 의 어 려 운 점 을 알 아 보 는 글
뷰 그룹 을 어떻게 사용자 정의 하고 레이아웃 을 사용자 정의 하 며 사용자 정의 측정 을 어떻게 쓰 는 지 알려 주 는 것 이 목적 이다.많은 인터넷 에서 마음대로 검색 하 는 개념 과 절차 도
여기 서 더 이상 설명 하지 않 겠 습 니 다.본 고 를 보기 전에 기본 적 인 사용자 정의 view group 절 차 를 살 펴 보고 마음 속 에 대략적인 것 이 있 으 면 됩 니 다.본문 은 실천 을 중시한다.
viewgroup 의 측정 레이아웃 프로 세 스 기본 정리
기본 적 인 viewgroup 그리 기와 레이아웃 프로 세 스 의 중점 을 살 펴 보 겠 습 니 다.
1.view 는 onMeasure()방법 에서 자체 측정 과 보존 을 한다.즉,view(view group 아 닙 니 다)에 있어 서 반드시 onMeasure 방법 에서 자신의 사 이 즈 를 계산 하여 저장 해 야 한다.
2.viewgroup 은 실제 적 으로 위 크기 에서 하위 view 를 호출 하 는 measure 방법 이기 도 합 니 다.하위 view 의 measure 가 실제 적 으로 하위 view 의 onMeasure 방법 을 호출 하 는 것 을 주의 하 십시오.그래서 우 리 는 이 과정 을 다음 과 같이 이해한다.
view group 순환 은 모든 하위 view 의 onmeasure 방법 을 호출 하고 onmeasure 방법 으로 계 산 된 크기 를 이용 하여 이 하위 view 가 최종 적 으로 사용 할 수 있 는 크기 와 배치 위 치 를 확인 합 니 다.
3.measure 방법 은 final 방법 으로 측정 작업 준비 작업 으로 이해 할 수 있 습 니 다.final 방법 이기 때문에 우 리 는 그것 을 다시 쓸 수 없습니다.너무 많이 필요 하지 않 습 니 다.
그 를 주목 하 라.measure 가 최종 적 으로 onmeasure 를 호출 해 야 하기 때문에 이 onmeasure 는 우리 가 다시 쓸 수 있다.이거 지 켜 봐 야 돼.layot 와 onlayout 은 같은 관계 입 니 다.
4.부모 view 가 하위 view 의 layot 방법 을 호출 할 때 이전 measure 단계 에서 확 정 된 위치 와 크기 를 하위 view 에 전달 합 니 다.
5.사용자 정의 view/viewgroup 에 있어 우 리 는 다음 세 가지 수요 에 만 관심 을 가 져 야 합 니 다.
4.567917.기 존의 안 드 로 이 드 자체 view 에 대해 우 리 는 그의 onMeasure 방법 만 다시 쓰 면 된다.이 사 이 즈 를 수정 하면 수 요 를 완성 할 수 있 습 니 다
7.부모 view 가 자식 view 에 대한 제한 을 어떻게 이해 합 니까?
onMeasure 의 두 매개 변 수 는 부모 view 의 하위 view 에 대한 제한 이 므 로 이 제한 값 은 도대체 어디에서 나 온 것 입 니까?
실제로 부모 view 의 하위 view 에 대한 제한 은 대부분 우리 개발 자가 설정 한 layot 에서 시작 하 는 속성 입 니 다.
예 를 들 어 우 리 는 imageview 에 그의 layot 를 설정 했다.width 와 layotheight 이 두 가지 속성,그럼 이 두 가지 속성 은 사실 우리 개발 자 입 니 다.
기대 하 는 넓 고 높 은 속성,하지만 주의해 야 합 니 다.
설정 한 이 두 가지 속성 은 부모 view 에 보 여 주 는 것 입 니 다.실제 대부분의 layot 시작 속성 에 대해 서 는 부모 view 에 보 여 주 는 것 입 니 다.
왜 아버지 께 보 여 드 려 야 합 니까?부모 view 는 이러한 속성 을 알 아야 하위 view 의 측정 에 어떤 제한 을 가 해 야 하 는 지 알 수 있 기 때 문 입 니까?
도대체 무제 한(UNSPECIFIED)인가요?아니면 최대 치 제한(ATMOST),하위 뷰 가 이 값 을 초과 하지 않도록?아니면 죽음 을 직접 제한 하 든 내 가 시 키 는 대로 해 야 돼(EXACTLY).
Banner ImageView 수정 onMeasure 방법 사용자 정의
banner Imageview 란 많은 전자상거래 업 체 들 이 광고 도 를 방영 하 는 것 입 니 다.이 광고 도의 너비 와 높이 는 모두 가 변 적 입 니 다.우 리 는 일상적인 개발 과정 에서
또한 이러한 수 요 를 자주 접 할 수 있 습 니 다.imageview 의 너비 와 높이 는 하이파이 어 에 표 시 된 것 보다 높 지만 많은 핸드폰 의 화면 너비 나 높이 를 고려 하여 확실 하지 않 습 니 다.
그래서 우 리 는 보통 수 동 으로 이 imageview 의 높이 나 너 비 를 계산 한 다음 에 width 나 height 의 값 을 동적 으로 바 꿔 야 한다.이런 방법 은 쓸 수 있 지만 매우 번거롭다.
사용자 정의 imageview 를 보 여 줍 니 다.ratio 의 속성 을 설정 하면 iv 의 높이 를 동적 으로 설정 할 수 있 습 니 다.매우 편리 하 다
효 과 를 보다
마지막 으로 코드 를 보 세 요.중요 한 부분 은 주석 에 적 혀 있 습 니 다.더 이상 말 하지 않 겠 습 니 다.
public class BannerImageView extends ImageView {
//
float ratio;
public BannerImageView(Context context) {
super(context);
}
public BannerImageView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BannerImageView);
ratio = typedArray.getFloat(R.styleable.BannerImageView_ratio, 1.0f);
typedArray.recycle();
}
public BannerImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// , setMeasuredDimension
//
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//
int mWidth = getMeasuredWidth();
int mHeight = (int) (mWidth * ratio);
// , view 。 。
setMeasuredDimension(mWidth, mHeight);
}
}
사용자 정의 view,완전 자기 쓰기 onMeasure 방법먼저 명확 한 결론 을 내린다.
완전히 사용자 정의 view,완전히 자신 이 쓴 onMeasure 방법 에 있어 서,당신 이 저장 한 너비 와 높이 는 부모 view 의 제한 에 부합 되 어야 합 니 다.그렇지 않 으 면 bug 가 발생 합 니 다.
부모 view 의 하위 view 에 대한 제한 을 저장 하 는 방법 도 간단 합 니 다.resolve Size 방법 을 직접 호출 하면 됩 니 다.
그래서 완전히 사용자 정의 view onMeasure 방법 도 어렵 지 않 습 니 다.
4.567917.먼저 자신 이 원 하 는 너비 와 높이 를 계산한다.예 를 들 어 네가 원 을 그 렸 다 면 너비 와 높이 는 반지름 의 두 배 크기 일 것 이다.만약 에 원 아래 에 글자 가 있다 면4.567917.그러면 높이 는 반지름 의 두 배 를 제외 하고 글씨체 의 크기 가 있 을 것 이다.그렇지?간단 해.이것 은 순 전 히 사용자 정의 view 가 어떤 것 인지 에 달 려 있다.
4.567917.자신 이 원 하 는 너비 와 높이 를 계산 한 후에 resolve Size 방법 으로 처리 하면 됩 니 다마지막 setMeasured Dimension 저장.범례:
public class LoadingView extends View {
//
int radius;
// rect
int left = 10, top = 30;
Paint mPaint = new Paint();
public LoadingView(Context context) {
super(context);
}
public LoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LoadingView);
radius = typedArray.getInt(R.styleable.LoadingView_radius, 0);
}
public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = left + radius * 2;
int height = top + radius * 2;
// resolveSize view , layout bug 。
// view
width = resolveSize(width, widthMeasureSpec);
height = resolveSize(height, heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
RectF oval = new RectF(left, top,
left + radius * 2, top + radius * 2);
mPaint.setColor(Color.BLUE);
canvas.drawRect(oval, mPaint);
//
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(2);
canvas.drawArc(oval, -90, 360, false, mPaint);
}
}
레이아웃 파일:
<LinearLayout
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#000000"
android:orientation="horizontal">
<com.example.a16040657.customviewtest.LoadingView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/dly"
app:radius="200"></com.example.a16040657.customviewtest.LoadingView>
<com.example.a16040657.customviewtest.LoadingView
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/dly"
app:radius="200"></com.example.a16040657.customviewtest.LoadingView>
</LinearLayout>
마지막 효과:viewgroup 사용자 정의
이것 은 사실 조금 복잡 하지만 따라 갈 만 한 흔적 이 있 습 니 다.다만 약간의 추가 적 인 인내심 이 필요 합 니 다.
viewgroup 에서 주의해 야 할 점 은 다음 과 같 습 니 다.
4
고정 적 이 고 매우 간단 하 다 고 할 수 있 지만 참 새 는 작 지만 오장 이 모두 갖 추어 져 있 기 때문에 사용자 정의 viewgroup 의 관건 을 잘 이해 할 수 있 습 니 다.
/**
* flowlayout layout, layout
* , , flowlayout
* , viewgroup 。
* <p>
* padding margin , viewgroup
* 。。。。。。
*/
public class SimpleFlowLayout extends ViewGroup {
public SimpleFlowLayout(Context context) {
super(context);
}
public SimpleFlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SimpleFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* layout ,
* ,
* , onMeasure view
*
* @param changed
* @param l
* @param t
* @param r
* @param b
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childTop = 0;
int childLeft = 0;
int childRight = 0;
int childBottom = 0;
// width
int usedWidth = 0;
//customlayout
int layoutWidth = getMeasuredWidth();
Log.v("wuyue", "layoutWidth==" + layoutWidth);
for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
// view
int childWidth = childView.getMeasuredWidth();
int childHeight = childView.getMeasuredHeight();
//
if (layoutWidth - usedWidth < childWidth) {
childLeft = 0;
usedWidth = 0;
childTop += childHeight;
childRight = childWidth;
childBottom = childTop + childHeight;
childView.layout(0, childTop, childRight, childBottom);
usedWidth = usedWidth + childWidth;
childLeft = childWidth;
continue;
}
childRight = childLeft + childWidth;
childBottom = childTop + childHeight;
childView.layout(childLeft, childTop, childRight, childBottom);
childLeft = childLeft + childWidth;
usedWidth = usedWidth + childWidth;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// SimpleFlowLayout view SimpleFlowLayout 。
// view
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int usedWidth = 0; //
int remaining = 0; //
int totalHeight = 0; //
int lineHeight = 0; //
for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
LayoutParams lp = childView.getLayoutParams();
// view
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
//
remaining = widthSize - usedWidth;
// , view
if (childView.getMeasuredWidth() > remaining) {
// , 0
usedWidth = 0;
// ,
totalHeight = totalHeight + lineHeight;
}
// width
usedWidth = usedWidth + childView.getMeasuredWidth();
// view
lineHeight = childView.getMeasuredHeight();
}
// SimpleFlowLayout wrap cotent , , view SimpleFlowLayout
if (heightMode == MeasureSpec.AT_MOST) {
heightSize = totalHeight;
}
setMeasuredDimension(widthSize, heightSize);
}
}
마지막 으로 효 과 를 보 겠 습 니 다.총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.