Android 사용자 정의 ViewGroup 의 WaterfallLayout(2)
15683 단어 AndroidViewGroupWaterfallLayout
Android 에서 많은 사진 을 보 여 줘 야 할 때 우 리 는 GridView 를 사진 벽 으로 사용 할 수 있 습 니 다.그러나 GridView 는 너무 가지런 하고 불규칙 한 것 도 아름 답 습 니 다.폭포 흐름 모델 은 바로 이런 불규칙 한 전시 벽 입 니 다.그 다음 에 우 리 는 사용자 정의 ViewGroup 으로 폭포 흐름 을 실현 하려 고 합 니 다.
폭포 류 를 실현 하 는 방식 도 많 습 니 다.다음은 우리 가 하나씩 말씀 드 리 겠 습 니 다.
1.ViewGroup 계승
사실 이런 실현 방식 은 우 리 는 위의 블 로 그 를 바탕 으로 조금 만 수정 하면 된다.주로 이 몇 가 지 를 수정 할 수 있다.
•LayoutParams
폭포 흐름 에서 모든 그림 의 너비 가 같 고 높이 가 다 르 기 때문에 top 에 고정 높이 를 더 해서 bottom 을 얻 을 수 없 기 때문에 여기 서 나 는 아예 네 개의 매개 변 수 를 모두 정의 했다.
public static class LayoutParams extends ViewGroup.LayoutParams {
public int left = 0;
public int top = 0;
public int right = 0;
public int bottom = 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);
}
}
•onMeasure여 기 는 그림 마다 너비 가 같 고 높 은 비율 로 크기 를 조정 하기 때문에 Waterfall Layout 의 layotheight 소 용 없어 요.다음 에 그림 을 추가 할 때 높이 가 가장 작은 열 에 추가 할 수 있 도록 배열 top[colums]로 현재 높이 를 기록 합 니 다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
int childCount = this.getChildCount();
// 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;
}
// View onMeasure、onLayout ,
clearTop();
// view, LayoutParams , onLayout
for (int i = 0; i < childCount; i++) {
View child = this.getChildAt(i);
childHeight = child.getMeasuredHeight() * childWidth / child.getMeasuredWidth();
LayoutParams lParams = (LayoutParams) child.getLayoutParams();
int minColum = getMinHeightColum();
lParams.left = minColum * (childWidth + hSpace);
lParams.top = top[minColum];
lParams.right = lParams.left + childWidth;
lParams.bottom = lParams.top + childHeight;
top[minColum] += vSpace + childHeight;
}
// wrap_content , viewGroup
int wrapWidth;
int wrapHeight;
if (childCount < colums) {
wrapWidth = childCount * childWidth + (childCount - 1) * hSpace;
} else {
wrapWidth = colums * childWidth + (colums - 1) * hSpace;
}
wrapHeight = getMaxHeight();
setMeasuredDimension(widthMode == MeasureSpec.AT_MOST? wrapWidth:sizeWidth, wrapHeight);
}
•onLayout LayoutParams 는 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.right, lParams.bottom);
}
}
여기 서 주의해 야 할 부분 이 있 습 니 다.매번 하위 View 의 Layout Params 를 설정 하기 전에 top[]배열 을 0 으로 해 야 합 니 다.onMeasure 와 onLayout 는 두 번 호출 되 기 때문에 다음 설정 매개 변수 가 정확 하도록 확보 합 니 다.연장:왜 view Group 의 onMeasure 와 onLayout 방법 을 두 번 호출 합 니까?
왜냐하면 우리 가 new View Group()을 사용 할 때 getWidth()와 getHeight()를 통 해 얻 은 값 은 먼저 0,0 이 고 onMeasure()와 onLayout()방법 을 호출 하면 이 view 의 크기 를 측정 합 니 다.이때 view 의 너비 가 바 뀌 었 습 니 다.이 때 onMeasure 와 onLayout 방법 을 다시 호출 합 니 다(view 가 바 뀌 었 을 때,이 두 가지 방법 은 호출 될 것 이다.)이때 getWidth 와 getHeight 방법 을 통 해 측정 후의 너비 와 높이 를 볼 수 있다.이것 이 바로 두 번 호출 될 수 있 는 원인 이다.
•클릭 이벤트 리 셋
//
public interface OnItemClickListener {
void onItemClick(View v, int index);
}
public void setOnItemClickListener(final OnItemClickListener listener) {
for (int i = 0; i < getChildCount(); i++) {
final int index = i;
View view = getChildAt(i);
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listener.onItemClick(v, index);
}
});
}
}
WaterfallLayout 를 사용 하여 그림 추가 하기:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res/com.hx.waterfalllayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#303030"
android:orientation="vertical" >
<com.hx.waterfalllayout.WaterfallLayout
android:id="@+id/gridview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#1e1d1d"
app:hSpace="10"
app:numColumns="3"
app:vSpace="10" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/crazy_1" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/crazy_2" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/crazy_1" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/crazy_2" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/crazy_1" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/crazy_2" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/crazy_1" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/crazy_2" />
</com.hx.waterfalllayout.WaterfallLayout>
</ScrollView>
여기 서 가장 바깥쪽 에 우리 가 사용 하 는 ScrollView 는 사진 벽 에 사진 을 무한 추가 할 수 있 기 때문에 사진 의 수량 이 주파수 막 범 위 를 초과 한 후에 굴 러 갈 수 있 도록 합 니 다.그리고 여기 ImageView 는 모두 xml 에 쓰 여 있 습 니 다.물론 자바 에서 이 View Group 에 동적 으로 ImageView 를 추가 할 수 있 고 코드 가 더욱 아름 답 습 니 다.폭포 흐름 그림 의 클릭 이벤트 리 셋 함수 구현:
((WaterfallLayout) findViewById(R.id.waterfallLayout)).setOnItemClickListener(new com.hx.waterfalllayout.WaterfallLayout.OnItemClickListener() {
@Override
public void onItemClick(View v, int index) {
Toast.makeText(MainActivity.this, "item="+index, Toast.LENGTH_SHORT).show();
}
});
실행 효과 보기:연장:
일반적으로 사용자 정의 컨트롤 은 scrollview 에 끼 워 넣 으 면 불완전 하 게 표 시 됩 니 다.이 문 제 는 매우 복잡 합 니 다.그러나 scrollview 의 소스 코드 를 열 면 scrollview 에 끼 워 넣 은 viewpager,gridview,listview 를 이해 할 수 있 는 곳 이 있 습 니 다.
여기에 포 함 된 viewpager,gridview,listview 를 완전히 표시 할 수 있 는 작은 기술 이 있 습 니 다.예 를 들 어 우 리 는 자신의 Other GridView 를 Gridview 에 계승 하고 onMeasure 방법 을 다시 쓰 면 됩 니 다.다른 View Group 은 마찬가지 입 니 다.
public class OtherGridView extends GridView {
public OtherGridView(Context paramContext, AttributeSet paramAttributeSet) {
super(paramContext, paramAttributeSet);
}
/** ScrollView , */
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
2.계승 ScrollViewScrollView 를 계승 하 는 폭포 흐름 모형 은 그림 이 너무 많 으 면 미끄럼 식 이 필요 합 니 다.
이 때 onMesure 를 다시 쓸 필요 가 없습니다.onLayout 만 다시 쓸 수 있 습 니 다.
•onLayout
/**
* , ScrollWaterfallLayout , 。
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed && !loadOnce) {
firstColumn = (LinearLayout) findViewById(R.id.first_column);
secondColumn = (LinearLayout) findViewById(R.id.second_column);
thirdColumn = (LinearLayout) findViewById(R.id.third_column);
columnWidth = firstColumn.getWidth();
loadOnce = true;
loadImages();
}
}
•그림 불 러 오기
/**
*
*/
public void loadImages() {
for (int i = 0; i < imageRes.length; i++) {
Bitmap bitmap = resource2Bitmap(imageRes[i]);
if (bitmap != null) {
double ratio = bitmap.getWidth() / (columnWidth * 1.0);
int scaledHeight = (int) (bitmap.getHeight() / ratio);
addImage(i, bitmap, columnWidth, scaledHeight);
}
}
}
/**
* ImageView
*
* @param bitmap
*
* @param imageWidth
*
* @param imageHeight
*
*/
private void addImage(int index, Bitmap bitmap, int imageWidth, int imageHeight) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(imageWidth, imageHeight);
ImageView imageView = new ImageView(getContext());
imageView.setLayoutParams(params);
imageView.setImageBitmap(bitmap);
imageView.setScaleType(ScaleType.FIT_XY);
imageView.setPadding(5, 5, 5, 5);
findColumnToAdd(imageView, imageHeight).addView(imageView);
//
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(v, index);
}
}
});
}
/**
* 。 , 。
*
* @param imageView
* @param imageHeight
* @return
*/
private LinearLayout findColumnToAdd(ImageView imageView,int imageHeight) {
if (firstColumnHeight <= secondColumnHeight) {
if (firstColumnHeight <= thirdColumnHeight) {
firstColumnHeight += imageHeight;
return firstColumn;
}
thirdColumnHeight += imageHeight;
return thirdColumn;
} else {
if (secondColumnHeight <= thirdColumnHeight) {
secondColumnHeight += imageHeight;
return secondColumn;
}
thirdColumnHeight += imageHeight;
return thirdColumn;
}
}
여기까지 폭포 흐름 사진 벽 을 표시 할 수 있 습 니 다.편리 하 죠?그러나 이런 방식 도 한계 가 있다.예 를 들 어 여기 열 폭 이 3 열 로 쓰 여 져 있어 확장 성 이 좋 지 않다.코드 에서 우 리 는 사용자 정의 ViewGroup 이 모든 childView 를 실현 하 는 layot 방법 을 보지 못 했 습 니 다.그러면 childView 는 어떻게 배치 합 니까?사실 childView 의 레이아웃 은 LinearLayout 를 통 해 이 루어 집 니 다.즉,LinearLayout 내부 에서 모든 childView 의 layot 방법 을 호출 했 습 니 다.이것 은 이전에 우리 가 사용자 정의 View 를 말 했 을 때의 조합 컨트롤 과 비슷 하지 않 습 니까?
findColumnToAdd(imageView, imageHeight).addView(imageView);
•정의 그림 클릭 리 셋 인터페이스
//
public OnItemClickListener onItemClickListener;
public interface OnItemClickListener {
void onItemClick(View v, int index);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
•ScrollWaterfallLayout 사용 하기코드 에 세 열 만 지정 되 어 있 기 때문에 xml 는 세 개의 수평 으로 배 치 된 LinearLayout 가 필요 합 니 다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<com.hx.waterfalllayout.ScrollWaterfallLayout
android:id="@+id/scrollWaterfallLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<LinearLayout
android:id="@+id/first_column"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical" >
</LinearLayout>
<LinearLayout
android:id="@+id/second_column"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical" >
</LinearLayout>
<LinearLayout
android:id="@+id/third_column"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
</com.hx.waterfalllayout.ScrollWaterfallLayout>
</LinearLayout>
폭포 흐름 그림 의 클릭 이벤트 리 셋 함수 구현:
((ScrollWaterfallLayout)findViewById(R.id.scrollWaterfallLayout)).setOnItemClickListener(new com.hx.waterfalllayout.ScrollWaterfallLayout.OnItemClickListener() {
@Override
public void onItemClick(View v, int index) {
Toast.makeText(MainActivity.this, "item="+index, Toast.LENGTH_SHORT).show();
}
});
실행 효과:원본 다운로드:http://xiazai.jb51.net/201609/yuanma/Android-WaterfallLayout(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에 따라 라이센스가 부여됩니다.