Android 에서 Layout Inflater 를 사용 할 때 주의해 야 할 구덩이 들
7747 단어 androidlayoutinflater
평소에 개발 하 는 과정 에서 우 리 는 Layout Inflater 라 는 종 류 를 자주 사용한다.예 를 들 어
Fragment$onCreateView
과 RecyclerView.Adapter$onCreateViewHolder
에서 모두 사용한다.그것 의 용법 도 LayoutInflater.inflate(resourceId, root, attachToRoot)
일 뿐 첫 번 째 매개 변 수 는 할 말 이 없 지만 두 번 째 매개 변수 와 세 번 째 매개 변 수 를 결합 하면 어느 정도 현혹 성 을 가 져 올 것 이다.그 전에 가끔 인터페이스 구조 에 문제 가 생 긴 것 을 발견 할 수 있 습 니 다.한참 을 조사 한 후에 우연히 이 두 개의 매개 변 수 를 바 꾸 었 습 니 다.문 제 를 해결 한 후에 지나 갔습니다.이것 이 왜 그런 지 생각 하지 않 았 습 니 다.그리고 다음 에 이런 곤경 을 반복 할 수 있 습 니 다.그래서 여기 서 정리 해서 나중에 계속 구덩이 에 빠 지지 않도록 하려 고 합 니 다.
먼저 inflate 방법의 주석 을 보십시오.
/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
*
* @param resource ID for an XML layout resource to load (e.g.,
* <code>R.layout.main_page</code>)
* @param root Optional view to be the parent of the generated hierarchy (if
* <em>attachToRoot</em> is true), or else simply an object that
* provides a set of LayoutParams values for root of the returned
* hierarchy (if <em>attachToRoot</em> is false.)
* @param attachToRoot Whether the inflated hierarchy should be attached to
* the root parameter? If false, root is only used to create the
* correct subclass of LayoutParams for the root view in the XML.
* @return The root View of the inflated hierarchy. If root was supplied and
* attachToRoot is true, this is root; otherwise it is the root of
* the inflated XML file.
*/
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
먼저 알 아야 할 것 은 하나의 View 의 측정 결 과 는 자신의 layot 만 있 는 것 이 아니 라 는 것 입 니 다.width 와 layotheight(즉 LayoutParams)는 부모 용기 가 주 는 제약(MeasureSpec)과 자신의 LayoutParams 가 공동으로 결정 합 니 다.이 공감 대 를 형성 한 후에 우 리 는 그것 의 인 자 를 다시 한 번 보 자.
root != null && attachToRoot
이면 돌아 오 는 View 는 들 어 오 는 root 입 니 다.그렇지 않 으 면 레이아웃 파일 로 만 든 View 대상 을 되 돌려 줍 니 다.
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_text"
android:layout_width="200dp"
android:layout_height="50dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:background="@color/colorAccent"
android:gravity="center"
android:text="item: text"/>
정상 적 인 상황
//
View inflatedView = LayoutInflater.from(this).inflate(R.layout.item_text, mLinearLayout, true);
Log.d(TAG, "inflated view is " + inflatedView);
//
View inflatedView = LayoutInflater.from(this).inflate(R.layout.item_text, mLinearLayout, false);
Log.d(TAG, "inflated view is " + inflatedView);
mLinearLayout.addView(inflatedView);
시각 적 인 결 과 는 모두 같다.그러나 Log 는 조금 다 릅 니 다.이것 이 바로 attachToRoot 의 서로 다른 값 으로 인 한 것 입 니 다.
첫 번 째 방법의 Log
D/MainActivity: inflated view is android.widget.LinearLayout{36e9aac V.E...... ......I. 0,0-0,0 #7f0c0051 app:id/linear}
두 번 째 방법의 Log
D/MainActivity: inflated view is android.support.v7.widget.AppCompatTextView{3c9d37b V.ED..... ......ID 0,0-0,0 #7f0c0054 app:id/item_text}
또 주의해 야 할 점 은 첫 번 째 방법 에 mLinearLayout.addView(inflatedView)
을 더 하면 오류 가 발생 할 수 있다 는 것 이다.IllegalStateException: The specified child already has a parent....
。두 번 째 방법 이 이 말 이 없 으 면 화면 에 아무것도 보이 지 않 는 다.
루트 가 null 인 경우
mLinearLayout = (LinearLayout) findViewById(R.id.linear);
View inflatedView = LayoutInflater.from(this).inflate(R.layout.item_text, null);
Log.d(TAG, "inflated view is " + inflatedView);
mLinearLayout.addView(inflatedView);
이 때 레이아웃 파일 을 보십시오:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_text"
android:layout_width="200dp"
android:layout_height="50dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:background="@color/colorAccent"
android:gravity="center"
android:text="item: text"/>
어렵 지 않 게 모든 layotxxx 의 속성 이 모두 효력 을 잃 었 습 니 다.RecyclerView 의 Inflater
위 에서 말 했 듯 이 레이아웃 을 만 들 때 루트 에 레이아웃 을 추가 하고 두 가지 방법 이 있 습 니 다.그러나 우 리 는 onCreate View Holder 에 레이아웃 을 추가 할 때 이렇게 썼 습 니 다.
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_text, parent, false);
return new MyViewHolder(view);
}
세 번 째 매개 변수 가 true 를 전달 하면 잘못 보고 할 수 있 습 니 다.왜 일 까요?
java.lang.IllegalStateException: The specified child already has a parent.
직관 적 으로 보면 서브 뷰 의 추가 와 삭 제 는 RecyclerView 가 관리 하 는 것 이 므 로 우리 가 추가 할 필요 가 없다 는 것 이다.그래도 RecyclerView 코드 로 이해 하 는 게 좋 을 것 같 아 요.LinearLayoutManager 의 경우 RecyclerView 는 하위 View 를 만 들 때
LinearLayoutManager$layoutChunk
방법 으로 호출 됩 니 다.
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
LayoutState layoutState, LayoutChunkResult result) {
// Adapter$onCreateViewHolder
View view = layoutState.next(recycler);
if (view == null) {
if (DEBUG && layoutState.mScrapList == null) {
throw new RuntimeException("received null view when unexpected");
}
// if we are laying out views in scrap, this may return null which means there is
// no more items to layout.
result.mFinished = true;
return;
}
LayoutParams params = (LayoutParams) view.getLayoutParams();
if (layoutState.mScrapList == null) {
if (mShouldReverseLayout == (layoutState.mLayoutDirection
== LayoutState.LAYOUT_START)) {
addView(view);
} else {
addView(view, 0);
}
} else {
if (mShouldReverseLayout == (layoutState.mLayoutDirection
== LayoutState.LAYOUT_START)) {
addDisappearingView(view);
} else {
addDisappearingView(view, 0);
}
}
//
}
초기 화 할 때 View view = layoutState.next(recycler)
에서 우리 가 익숙 한 onCreateViewHolder
방법 으로 호출 됩 니 다.그리고 우 리 는 안에서 inflate 를 하 는 과정 에서 세 번 째 매개 변 수 는 true 를 전달 하고 서브 View 를 RecyclerView 에 추가 합 니 다.그러나 View 를 얻 은 후 addView 로 호출 되 었 습 니 다.총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 안 드 로 이 드 개발 자 들 에 게 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.