Android 사용자 정의 ViewGroup 구현 방법

안 드 로 이 드 에서 흔히 볼 수 있 는 몇 가지 View Group 의 실현 을 제 공 했 는데 LinearLayout,Relativeayout,FrameLayout 등 을 포함한다.이러한 View Group 은 우리 의 일반적인 개발 수 요 를 만족 시 킬 수 있 지만 인터페이스 에 대한 요구 가 복잡 한 것 에 대해 이 몇 가지 구 조 는 매우 부족 해 보인다.그래서 사용자 정의 뷰 그룹 은 우리 가 접 한 응용 프로그램 에서 비 일비 재 하 다.
     사용자 정의 ViewGroup 을 실현 하려 면 첫 번 째 단 계 는 사용자 정의 속성 을 배 우 는 것 입 니 다.이러한 사용자 정의 속성 은 레이아웃 파일 을 설정 할 때 더욱 유연 해 집 니 다.사용자 정의 속성 은 value 디 렉 터 리 아래 attrs.xml 파일 을 설명 합 니 다.

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="CascadeViewGroup">
  <attr name="verticalspacing" format="dimension"/>
  <attr name="horizontalspacing" format="dimension"/>
 </declare-styleable>

 <declare-styleable name="CascadeViewGroup_LayoutParams">
  <attr name="layout_paddingleft" format="dimension"/>
  <attr name="layout_paddinTop" format="dimension"/>
 </declare-styleable>
</resources>

      여기에서 우 리 는 두 개의 사용자 정의 속성 집합 을 설명 합 니 다.CascadeViewGroup 의 속성 은 우리 가 사용자 정의 한 CascadeViewGroup 구성 요 소 를 대상 으로 설정 한 것 입 니 다.즉,레이아웃 파일 에서탭 에서 사용 할 수 있 는 속성 입 니 다.또 다른 캐 스 케 이 드 뷰 그룹LayoutParams 는 CascadeView Group 의 하위 View 설정 에 대한 속성 입 니 다.
    코드 를 작성 하기 전에 캐 스 케 이 드 레이아웃 에 사용 할 기본 너비 와 높이 를 설정 합 니 다.이 두 속성 은 dimens.xml 에서 정의 합 니 다.

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <dimen name="default_horizontal_spacing">10dp</dimen>
 <dimen name="default_vertical_spacing">10dp</dimen>
</resources>

다음은 사용자 정의 구성 요소 인 CascadeLayout 를 작성 합 니 다.

package com.app.CustomViewMotion;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by charles on 2015/8/13.
 */
public class CascadeViewGroup extends ViewGroup {

 //              
 private int mHoriztonalSpacing;
 private int mVerticalSpacing;

 public CascadeViewGroup(Context context) {
  this(context, null);
 }

 public CascadeViewGroup(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
 }

 public CascadeViewGroup(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CascadeViewGroup);
  try {
   //       
   mHoriztonalSpacing = a.getDimensionPixelSize(R.styleable.CascadeViewGroup_horizontalspacing,
     this.getResources().getDimensionPixelSize(R.dimen.default_horizontal_spacing));
   //       
   mVerticalSpacing = a.getDimensionPixelSize(R.styleable.CascadeViewGroup_verticalspacing,
     this.getResources().getDimensionPixelSize(R.dimen.default_vertical_spacing));

  } catch (Exception e) {
   e.printStackTrace();

  } finally {
   a.recycle();
  }
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  final int count = this.getChildCount();
  int width = this.getPaddingLeft();
  int height = this.getPaddingTop();
  for (int i = 0; i < count; i++) {
   final View currentView = this.getChildAt(i);
   this.measureChild(currentView, widthMeasureSpec, heightMeasureSpec);
   CascadeViewGroup.LayoutParams lp = (CascadeViewGroup.LayoutParams) currentView.getLayoutParams();
   if(lp.mSettingPaddingLeft != 0){
    width +=lp.mSettingPaddingLeft;
   }
   if(lp.mSettingPaddingTop != 0){
    height +=lp.mSettingPaddingTop;
   }
   lp.x = width;
   lp.y = height;
   width += mHoriztonalSpacing;
   height += mVerticalSpacing;
  }
  width +=getChildAt(this.getChildCount() - 1).getMeasuredWidth() + this.getPaddingRight();
  height += getChildAt(this.getChildCount() - 1).getMeasuredHeight() + this.getPaddingBottom();
  this.setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec));

 }

 @Override
 protected void onLayout(boolean b, int l, int i1, int i2, int i3) {
  final int count = this.getChildCount();
  for (int i = 0; i < count; i++) {
   final View currentView = this.getChildAt(i);
   CascadeViewGroup.LayoutParams lp = (CascadeViewGroup.LayoutParams) currentView.getLayoutParams();
   currentView.layout(lp.x, lp.y, lp.x + currentView.getMeasuredWidth(),
     lp.y + currentView.getMeasuredHeight());
  }


 }

 public static class LayoutParams extends ViewGroup.LayoutParams {
  int x;
  int y;
  int mSettingPaddingLeft;
  int mSettingPaddingTop;

  public LayoutParams(Context c, AttributeSet attrs) {
   super(c, attrs);
   TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.CascadeViewGroup_LayoutParams);
   mSettingPaddingLeft = a.getDimensionPixelSize(R.styleable.CascadeViewGroup_LayoutParams_layout_paddingleft, 0);
   mSettingPaddingTop = a.getDimensionPixelSize(R.styleable.CascadeViewGroup_LayoutParams_layout_paddinTop, 0);
   a.recycle();
  }

  public LayoutParams(int width, int height) {
   super(width, height);
  }

  public LayoutParams(ViewGroup.LayoutParams source) {
   super(source);
  }
 }

 @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
 public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
  return new LayoutParams(this.getContext(), attrs);
 }
}

코드 는 약간 장점 이 길 지만 구 조 는 뚜렷 합 니 다.
1)구조 방법 이나 XML 파일 에 속성 값 을 설정 합 니 다.TypedArray 의 방법 을 통 해 레이아웃 레이아웃 에 설 정 된 속성 을 가 져 오고 구성원 변수 에 저장 합 니 다.
2)사용자 정의 내부 클래스 LayoutParams 를 구성 합 니 다.이 내부 클래스 를 구성 하면 Layout 단계 에서 배치 할 수 있 도록 하위 View 를 측정 할 때 속성 값 을 저장 할 수 있 습 니 다.
3)generateLayoutParams(),generateDefaultParams()등 방법.이 방법 들 에서 사용자 정의 layoutParams 를 되 돌려 줍 니 다.왜 이런 방법 을 다시 써 야 하 는 지 에 대해 서 는 View Group 류 의 addView()방법 을 보면 알 수 있 습 니 다.
4)measure 단계.measure 단계 에서 저 희 는 자신의 크기 를 측정 하 는 동시에 하위 View 의 크기 도 측정 하고 하위 View 의 정 보 를 Layout Params 에 저장 합 니 다.
5)layot 단계.각 키 View 의 정보 에 따라 그들의 위 치 를 배치 합 니 다.
마지막 으로 레이아웃 파일 을 추가 합 니 다.

<?xml version="1.0" encoding="utf-8"?>
<!--        viewGroup-->
<!--                .xml        -->
<com.app.CustomViewMotion.CascadeViewGroup
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:ts="http://schemas.android.com/apk/res/com.app.CustomViewMotion"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  ts:horizontalspacing="15dp"
  ts:verticalspacing="15dp">

 <TextView android:layout_width="100dp"
    android:layout_height="100dp"
    android:gravity="center"
    android:text="text1"
    android:background="#668B8B"/>

 <TextView android:layout_width="100dp"
    android:layout_height="100dp"
    android:gravity="center"
    android:text="text2"
    android:background="#FFDAB9"/>

 <TextView android:layout_width="100dp"
    android:layout_height="100dp"
    android:gravity="center"
    android:text="text3"
    android:background="#43CD80"/>

<!--   view       view  -->
 <TextView android:layout_width="100dp"
    android:layout_height="100dp"
    android:gravity="center"
    android:text="text4"
    ts:layout_paddingleft="100dp"
    ts:layout_paddinTop="100dp"
    android:background="#00CED1"/>
</com.app.CustomViewMotion.CascadeViewGroup>



실현 효 과 는 다음 과 같다.

이상 의 모든 내용 입 니 다.참고 해 주시 고 많은 응원 부 탁 드 리 겠 습 니 다.

좋은 웹페이지 즐겨찾기