카테고리
사용자 정의 레이아웃은 두 가지 상황으로 나눌 수 있습니다.
ViewGroup을 맞춤설정하고 LinearLayout, RelativeLayout 등과 다른 일부 ViewGroup을 만듭니다. 예: API 14 이후에 추가된 GridLayout, 디자인 지원 라이브러리의 CoordinatorLayout 등
일부 기존 레이아웃을 사용자 정의하고 몇 가지 특수 기능을 추가하세요. 예: TableLayout 및 PercentFrameLayout(퍼센트 지원 라이브러리 등)
프로세스
사용자 정의 뷰 프로세스는 onMeasure()->onLayout()->onDraw()입니다. ViewGroup을 사용자 정의할 때 일반적으로 onDraw를 구현할 필요는 없습니다. 물론 CoordinatorLayout과 같은 특별한 요구 사항이 있을 수 있습니다.
따라서 onMeasure와 onLayout은 기본적으로 우리가 접촉하는 대부분의 ViewGroup을 수행할 수 있습니다. 하지만 onMeasure에서 ViewGroup의 크기를 측정하고 onLayout에서 Child View의 위치를 계산하는 방법을 아는 것만으로는 충분하지 않습니다.
예: ViewGroup의 하위 뷰에 대한 속성을 어떻게 설정할 수 있습니까?
예시.
사용자 정의 ViewGroup을 작성하고 ViewGroup에 비례하여 하위 뷰의 크기(길이 및 너비)를 제어하는 속성을 추가합니다.
LinearLayout이라고 가정하고 먼저 CustomLinearLayout을 정의하세요.
public class CustomLinearLayout extends LinearLayout { public CustomLinearLayout(Context context) { super(context); } public CustomLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } }
다른 사항은 제쳐두고, 하위 뷰의 크기를 제어하려면 속성을 추가해야 합니다. 그런 다음 먼저 value/attr.xml에서 해당 속성을 정의합니다(CustomLinearLayout_Layout을 사용하여 CustomLinearLayout과 구별합니다. 물론 이름은 임의적입니다).
<declare-styleable name="CustomLinearLayout_Layout"> <!-- 定义比例 --> <attr name="inner_percent" format="float"/> </declare-styleable>
이 메소드는 결국 ViewGroup이 addView()를 호출할 때 호출됩니다.
public void addView(View child, int index, LayoutParams params)
이 매개변수는 View의 구성을 나타냅니다. ViewGroup.LayoutParams에는 너비와 높이가 포함되고, LinearLayout.LayoutParams에는 가중치 속성 등이 추가됩니다. 그런 다음 LayoutParams를 구현해야 합니다. 그래서 지금은 그게 다입니다.
public class CustomLinearLayout extends LinearLayout { public CustomLinearLayout(Context context) { super(context); } public CustomLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } public static class LayoutParams extends LinearLayout.LayoutParams { private float innerPercent; private static final int DEFAULT_WIDTH = WRAP_CONTENT; private static final int DEFAULT_HEIGHT = WRAP_CONTENT; public LayoutParams() { super(DEFAULT_WIDTH, DEFAULT_HEIGHT); innerPercent = -1.0f; } public LayoutParams(float innerPercent) { super(DEFAULT_WIDTH, DEFAULT_HEIGHT); this.innerPercent = innerPercent; } public LayoutParams(ViewGroup.LayoutParams p) { super(p); } @TargetApi(Build.VERSION_CODES.KITKAT) public LayoutParams(LinearLayout.LayoutParams source) { super(source); } @TargetApi(Build.VERSION_CODES.KITKAT) public LayoutParams(LayoutParams source) { super(source); this.innerPercent = source.innerPercent; } public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); init(c, attrs); } private void init(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomLinearLayout_Layout); innerPercent = a.getFloat(R.styleable.CustomLinearLayout_Layout_inner_percent, -1.0f); a.recycle(); } } }
이제 XML에서 속성을 사용할 수 있습니다.
으르르
부드러울 뿐 효과는 없어요.
그럼 어린이 화면 크기는 어떻게 조절하나요? 물론 onMeasure에서 제어됩니다. addView는 다음 코드를 실행합니다.
<?xml version="1.0" encoding="utf-8"?> <com.egos.samples.custom_layout.CustomLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="200dp" android:layout_height="200dp" android:id="@+id/test_layout" android:background="#ffff0000" android:gravity="center" android:orientation="vertical"> <ImageView android:text="Egos" android:layout_width="match_parent" android:layout_height="match_parent" android:onClick="add" android:background="#ff00ff00" app:inner_percent="0.8"/> </com.egos.samples.custom_layout.CustomLinearLayout>
이 경우 onMeasure() 및 onLayout()이 다시 탐색됩니다. onMeasure() 메서드를 구현한 후에는 LinearLayout을 상속하므로 실제로는 Child View의 크기를 처리하게 됩니다. 마지막 단계는 ChildBeforeLayout을 측정할 때 하위 뷰의 크기를 처리하는 것입니다.
requestLayout(); invalidate(true);
이렇게 하면 초기 요구 사항을 달성할 수 있습니다.
사실 아직 처리해야 할 세부 사항이 남아 있는데, 다음 코드는 다음과 같습니다.
@Override protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { // 在xml强制写成match_parent,然后在这里强制设置成 if (child != null && child.getLayoutParams() instanceof LayoutParams && ((LayoutParams) child.getLayoutParams()).innerPercent != -1.0f) { parentWidthMeasureSpec = MeasureSpec.makeMeasureSpec((int) (MeasureSpec.getSize(parentWidthMeasureSpec) * ((LayoutParams) child.getLayoutParams()).innerPercent), MeasureSpec.getMode(parentWidthMeasureSpec)); parentHeightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (MeasureSpec.getSize(parentHeightMeasureSpec) * ((LayoutParams) child.getLayoutParams()).innerPercent), MeasureSpec.getMode(parentHeightMeasureSpec)); super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed); } else { super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed); } }
요약하자면
View와 ViewGroup을 커스터마이징할 때 더 주의해야 할 것은 onMeasure, onLayout, onDraw입니다.
ViewGroup 자체의 속성과 하위 뷰의 속성을 분리합니다.
지원 패키지에 있는 코드를 참고할 수 있고, 디버깅도 매우 편리합니다.
Android 개발을 하다 보면 뷰를 맞춤설정해야 하는 곳이 실제로 많지만 대부분 해당 오픈 소스 라이브러리가 있습니다. 하지만 우리는 여전히 ViewGroup을 사용자 정의하는 방법을 능숙하게 알아야 합니다.
Android에서 사용자 정의 ViewGroup 사용 요약과 관련된 더 많은 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!