Android 사용자 정의 ViewGroup 의 CustomGridLayout(1)
13498 단어 AndroidViewGroupCustomGridLayout
우 리 는 View Group 이 바로 View 의 용기 류 라 는 것 을 알 고 있 습 니 다.우리 가 자주 사용 하 는 LinearLayout,Relative Layout 등 은 모두 View Group 의 하위 클래스 입 니 다.또한 레이아웃 xml 을 쓸 때 용기(layot 로 시작 하 는 속성 은 모두 용기 에 알려 주기 위 한 것),우리 의 너비(layotwidth),높이(layoutheight),정렬 방식(layotgravity)등;따라서 View Group 의 기능 은 childView 에 건의 하 는 너비 와 높이 와 측정 모델 을 계산 하 는 것 이다.childView 의 위 치 를 결정 합 니 다.왜 직접 확인 하 는 것 이 아니 라 너비 와 높이 만 권장 하 는 지 잊 지 마 세 요.childView 너비 와 높이 는 wrap 로 설정 할 수 있 습 니 다.content,이렇게 해야만 childView 만 이 자신의 너비 와 높이 를 계산 할 수 있 습 니 다.
View 는 ViewGroup 에서 들 어 오 는 측정 값 과 패턴 에 따라 자신의 너비 와 높이 를 확인 한 다음 에 onDraw 에서 자신 에 대한 그리 기 를 완성 합 니 다.ViewGroup 은 View 에 view 의 측정 값 과 모드(onMeasure 에서 완료)를 전달 해 야 하 며,이 ViewGroup 의 부모 레이아웃 에 대해 서도 onMeasure 에서 자신의 너비 와 높이 를 확인 해 야 합 니 다.또한,onLayout 에서 childView 의 위 치 를 지정 해 야 합 니 다.
ViewGroup 에는 하위 View 가 많 기 때문에 전체 그리 기 과정 은 View 에 비해 복잡 하지만 세 가지 절차 measure,layot,draw 에 따라 차례대로 설명 합 니 다.
본 고 는 GridView 와 유사 한 격자 용 기 를 쓰 자.우선 Custom GridView 라 고 부른다.
사용자 정의 속성/속성 값 가 져 오기
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomGridView">
<attr name="numColumns" format="integer" />
<attr name="hSpace" format="integer" />
<attr name="vSpace" format="integer" />
</declare-styleable>
</resources>
public CustomGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.CustomGridView);
colums = a.getInteger(R.styleable.CustomGridLayout_numColumns, 3);
hSpace = a.getInteger(R.styleable.CustomGridLayout_hSpace, 10);
vSpace = a.getInteger(R.styleable.CustomGridLayout_vSpace, 10);
a.recycle();
}
}
public MyGridLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyGridLayout(Context context) {
this(context, null);
}
LayoutParams ViewGroup 에 중요 한 지식 이 하나 더 있 습 니 다.LayoutParams 는 하위 View 가 ViewGroup 에 가입 할 때의 매개 변수 정 보 를 저장 합 니 다.ViewGroup 클래스 를 계승 할 때 보통 새로운 LayoutParams 클래스 를 새로 만들어 야 합 니 다.SDK 에서 우리 가 잘 아 는 LinearLayout.LayoutParams,RelativeLayout.LayoutParams 클래스 등 과 같이 이렇게 할 수 있 습 니 다.정 의 된 ViewGroup 하위 클래스 에 LayoutParams 클래스 계승 과 ViewGroup.LayoutParams 를 새로 만 듭 니 다.
public static class LayoutParams extends ViewGroup.LayoutParams {
public int left = 0;
public int top = 0;
public LayoutParams(Context arg0, AttributeSet arg1) {
super(arg0, arg1);
}
public LayoutParams(int arg0, int arg1) {
super(arg0, arg1);
}
public LayoutParams(android.view.ViewGroup.LayoutParams arg0) {
super(arg0);
}
}
이제 새로운 LayoutParams 클래스 가 생 겼 습 니 다.사용자 정의 ViewGroup 은 사용자 정의 LayoutParams 클래스 를 사용 하여 하위 View 를 추가 할 수 있 습 니까?ViewGroup 역시 다음 과 같은 몇 가지 방법 을 제공 합 니 다.사용자 정의 LayoutParams 대상 을 다시 쓰 면 됩 니 다.
@Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new CustomGridLayout.LayoutParams(getContext(), attrs);
}
@Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
@Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof CustomGridLayout.LayoutParams;
}
measure onMeasure 에서 두 가지 일 을 해 야 합 니 다.
•childView 의 측정 값 과 패턴 을 계산 합 니 다.
measureChildren(widthMeasureSpec, heightMeasureSpec);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
child.measure(WidthMeasureSpec, HeightMeasureSpec);
•ViewGroup 의 너비 와 높이 설정
View Group 의 크기 를 측정 합 니 다.layotwidth 와 layotheight 는 matchparent 또는 구체 적 인 xxxdp 는 간단 합 니 다.set Measured Dimension()방법 을 직접 호출 하여 View Group 의 너비 와 높이 를 설정 하면 됩 니 다.wrap 이 라면.content 는 비교적 번 거 롭 습 니 다.우 리 는 모든 하위 View 를 옮 겨 다 닌 다음 에 모든 하위 View 를 측정 한 다음 에 하위 View 의 배열 규칙 에 따라 최종 View Group 의 크기 를 계산 해 야 합 니 다.
메모:사용자 정의 View 첫 번 째 스 펙 모드 에서 UNSPECIFIED 는 일반적으로 부모 컨트롤 이 AdapterView 이 고 measure 방법 으로 들 어 오 는 모드 라 고 말 한 적 이 있 습 니 다.여기 서 마침 쓰 였 다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
//UNSPECIFIED AdapterView, measure
final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(sizeWidth, MeasureSpec.UNSPECIFIED);
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(sizeHeight, MeasureSpec.UNSPECIFIED);
measureChildren(childWidthMeasureSpec, childHeightMeasureSpec);
int childCount = this.getChildCount();
int line = childCount % colums == 0 ? childCount / colums : (childCount + colums) / colums;
// wrap_content ,childWidth childView ,
if (widthMode == MeasureSpec.AT_MOST) {
for (int i = 0; i < childCount; i++) {
View child = this.getChildAt(i);
childWidth = Math.max(childWidth, child.getMeasuredWidth());
}
} else if (widthMode == MeasureSpec.EXACTLY) {
childWidth = (sizeWidth - (colums - 1) * hSpace) / colums;
}
// wrap_content ,childHeight childView ,
if (heightMode == MeasureSpec.AT_MOST) {
for (int i = 0; i < childCount; i++) {
View child = this.getChildAt(i);
childHeight = Math.max(childHeight, child.getMeasuredHeight());
}
} else if (heightMode == MeasureSpec.EXACTLY) {
childHeight = (sizeHeight - (line - 1) * vSpace) / line;
}
// view, LayoutParams , onLayout
for (int i = 0; i < childCount; i++) {
View child = this.getChildAt(i);
LayoutParams lParams = (LayoutParams) child.getLayoutParams();
lParams.left = (i % colums) * (childWidth + hSpace);
lParams.top = (i / colums) * (childHeight + vSpace);
}
// wrap_content , viewGroup
int wrapWidth;
int wrapHeight;
if (childCount < colums) {
wrapWidth = childCount * childWidth + (childCount - 1) * hSpace;
} else {
wrapWidth = colums * childWidth + (colums - 1) * hSpace;
}
wrapHeight = line * childHeight + (line - 1) * vSpace;
setMeasuredDimension(widthMode == MeasureSpec.AT_MOST? wrapWidth:sizeWidth,heightMode == MeasureSpec.AT_MOST? wrapHeight:sizeHeight);
}
layout 가장 핵심 적 인 것 은 layot 방법 을 호출 하 는 것 입 니 다.우리 measure 단계 에서 얻 은 LayoutParams 의 left 와 top 필드 에 따라 모든 하위 View 에 위 치 를 배열 하 는 것 도 좋 습 니 다.
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = this.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = this.getChildAt(i);
LayoutParams lParams = (LayoutParams) child.getLayoutParams();
child.layout(lParams.left, lParams.top, lParams.left + childWidth, lParams.top + childHeight);
}
}
draw ViewGroup 은 draw 단계 에 있 습 니 다.사실은 하위 클래스 의 배열 순서에 따라 하위 클래스 의 onDraw 방법 을 호출 하 는 것 입 니 다.우 리 는 View 의 용기 일 뿐 그 자체 가 draw 추가 적 인 수식 이 필요 하지 않 기 때문에 onDraw 방법 에 서 는 ViewGroup 의 onDraw 기본 구현 방법 만 사용 하면 됩 니 다.다시 쓸 필요 없어.
마지막 으로 사용자 정의 ViewGroup 에서 GridAdatper 인 터 페 이 스 를 정의 하여 외부 에서 ViewGroup 에 어댑터 를 설정 할 수 있 도록 합 니 다.
public interface GridAdatper {
View getView(int index);
int getCount();
}
/** */
public void setGridAdapter(GridAdatper adapter) {
this.adapter = adapter;
//
int size = adapter.getCount();
for (int i = 0; i < size; i++) {
addView(adapter.getView(i));
}
}
또한 사용자 정의 ViewGroup 에서 OnitemClickListener 인 터 페 이 스 를 정의 하여 외부 에서 childView 의 클릭 이 벤트 를 가 져 올 수 있 도록 합 니 다.
public interface OnItemClickListener {
void onItemClick(View v, int index);
}
public void setOnItemClickListener(final OnItemClickListener listener) {
if (this.adapter == null)
return;
for (int i = 0; i < adapter.getCount(); i++) {
final int index = i;
View view = getChildAt(i);
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listener.onItemClick(v, index);
}
});
}
}
사용자 정의 CustomView Group 사용 하기레이아웃 파일:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res/com.hx.customgridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#303030"
android:orientation="vertical" >
<com.hx.customgridview.CustomGridLayout
android:id="@+id/gridview"
android:layout_width="200dp"
android:layout_height="300dp"
android:background="#1e1d1d"
app:hSpace="10"
app:vSpace="10"
app:numColumns="3"/>
</LinearLayout>
grid_item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"/>
</LinearLayout>
Java 파일:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
grid = (CustomGridLayout) findViewById(R.id.gridview);
grid.setGridAdapter(new GridAdatper() {
@Override
public View getView(int index) {
View view = getLayoutInflater().inflate(R.layout.grid_item, null);
ImageView iv = (ImageView) view.findViewById(R.id.iv);
iv.setImageResource(srcs[index]);
return view;
}
@Override
public int getCount() {
return srcs.length;
}
});
grid.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(View v, int index) {
Toast.makeText(MainActivity.this, "item="+index, Toast.LENGTH_SHORT).show();
}
});
}
}
실행 후 효과 그림 은 다음 과 같 습 니 다:레이아웃 변경:
<com.hx.customgridview.CustomGridLayout
android:id="@+id/gridview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#1e1d1d"
app:hSpace="10"
app:vSpace="10"
app:numColumns="3"/>
더욱 바꾼다
<com.hx.customgridview.CustomGridLayout
android:id="@+id/gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#1e1d1d"
app:hSpace="10"
app:vSpace="10"
app:numColumns="3"/>
재 변
<com.hx.customgridview.CustomGridLayout
android:id="@+id/gridview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#1e1d1d"
app:hSpace="10"
app:vSpace="10"
app:numColumns="4"/>
데모 다운로드 주소:http://xiazai.jb51.net/201609/yuanma/CustomGridLayout(jb51.net).rar
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.