LayoutInflater(레이아웃 서비스)


이 섹션 소개:

이 섹션에서는 Android 시스템 서비스의 LayoutInflater(레이아웃 서비스)를 계속해서 소개합니다. 여러분이 생각할 수 있는 것은 레이아웃 xml을 작성한 다음 Activity의 setContentView()를 호출하여 레이아웃을 로드하고 표시하는 것입니다. 화면에서는 그렇죠? 실제로 맨 아래 레이어는 여전히 Android에 내장된 Pull 파서를 사용하여 파싱되는 LayoutInflater입니다. 공들여 나열한 것. 일반적으로 Android에서는 레이아웃을 동적으로 로드하거나 컨트롤을 추가하는 데 더 일반적으로 사용됩니다. 이 섹션에서는 실제 개발에서 이를 사용하는 방법을 알아봅니다. 사용법~

공식 API 문서:LayoutInflater


1. LayoutInflater 관련 소개


1) 레이아웃이란?

답변: 레이아웃을 로드하는 데 사용되는 시스템 서비스는 레이아웃 XML 파일에 해당하는 View 개체를 인스턴스화하는 것입니다. 현재 컨텍스트에 바인딩된 콘텐츠를 가져오려면 getLayoutInflater() 메서드 또는 getSystemService() 메서드를 사용해야 합니다. LayoutInflater 인스턴스!


2) LayoutInflater 사용법

①LayoutInflater 인스턴스를 얻는 세 가지 방법:

LayoutInflater inflater1 = LayoutInflater.from(this);  
LayoutInflater inflater2 = getLayoutInflater();  
LayoutInflater inflater3 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);

PS: 후자 두 가지는 실제로 맨 아래 첫 번째 방법을 사용합니다~

②레이아웃 방법 로드 :

공개 보기 inflate (int 리소스, ViewGroup 루트, 부울 AttachToRoot) 이 메서드의 세 가지 매개변수는 다음과 같습니다.

1로드할 레이아웃에 해당하는 리소스 ID

2 레이아웃 외부에 상위 레이아웃의 다른 레이어를 중첩합니다. 필요하지 않으면 null을 씁니다.

3 루트 레이아웃 설정 여부 로드된 레이아웃 파일의 가장 바깥쪽 레이어에 대해 이 매개변수가 설정되지 않은 경우 루트가 null이 아닌 경우 기본값은 true입니다. 루트가 null인 경우, attachmentToRoot는 아무런 효과가 없습니다! 루트가 null이 아니고 attachmentToRoot가 true인 경우 루트 레이아웃은 로드된 레이아웃 파일의 가장 바깥쪽 레이어에 중첩됩니다. 거짓이면 루트는 기능을 잃게 됩니다! 간단한 이해는 다음과 같습니다. 로드된 레이아웃에 대해 루트 외부 컨테이너를 추가할지 여부~!


3LayoutInflater.LayoutParams를 통해 관련 속성 설정:

예를 들어 RelativeLayout은 addRule 메서드를 통해 규칙을 추가할 수도 있습니다. 위치만 설정하세요. 상위 컨테이너를 참조하나요? 아니면 어린이 통제를 참조합니까? 아니면 여백 등을 설정하세요~


2. 레이아웃을 로드하는 순수 Java 코드

우리는 오랫동안 XML을 사용하여 필요한 레이아웃을 생성하는 데 익숙했지만 일부 특정 경우에는 레이아웃에 구성 요소나 레이아웃을 동적으로 추가하려면 Java 코드를 사용해야 합니다.

하지만 Android 페이지 레이아웃을 작성하기 위해 Java 코드를 완전히 사용하는 것은 권장되지 않습니다. 첫 번째 요점은 코드가 많다는 것입니다. 엉망이 되기 쉽고 비즈니스 분할에 도움이 되지 않습니다. 여전히 xml을 사용하여 레이아웃을 완성한 다음 통과하는 것이 좋습니다. 물론 Java 코드는 내부 구성 요소를 수정하므로 구성 요소를 동적으로 추가하려면 Java를 사용해야 할 수도 있습니다.

순수 Java 코드 로딩 레이아웃 프로세스:


——1단계:

1컨테이너 만들기:LinearLayout ly = new LinearLayout(this);

컴포넌트 만들기:Button btnOne = new Button(this);

——2단계:

컨테이너 또는 구성 요소에 대한 관련 속성을 설정할 수 있습니다. 예: LinearLayout, 구성 요소의 배열 방향을 설정할 수 있습니다: ly.setOrientation(LinearLayout.VERTICAL);또한 구성 요소는 다음과 같을 수도 있습니다. 예: Button: btnOne.setText("Button 1") ;속성 설정 방법에 대해 Android API를 참조하세요. 일반적으로 xml로 설정된 속성은 setPadding(left, top, right, Bottom);

과 같이 앞에만 추가하면 됩니다. 3단계:

구성요소 또는 컨테이너 배치 이를 컨테이너에 추가합니다. 이때 구성요소의 추가 위치를 설정하거나 크기를 설정해야 할 수도 있습니다. LayoutParams 클래스를 사용해야 합니다. 이를 레이아웃 컨테이너의 위치와 크기에 대한 정보 패키지로 생각할 수 있습니다! 정보를 기다리는 클래스! 먼저 크기를 설정하는 방법을 보여줍니다. (이전의 LinearLayout은 다른 컨테이너에 따라 변경될 수 있습니다.)

LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(  
        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

는 매우 간단하며, 일반적으로 위치를 설정할 때 우리는 설정합니다. RelativeLayout만 고려하세요! 이때 LayoutParams의 addRule() 메소드를 사용합니다! addRule()을 여러 개 추가할 수 있습니다! 상위 컨테이너에서 구성 요소의 위치를 ​​설정합니다.

예를 들어 구성 요소 정렬 설정:

RelativeLayout rly = new RelativeLayout(this);  
RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
lp2.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);  
Button btnOne = new Button(this);  
rly.addView(btnOne, lp2);

다른 구성 요소 정렬 참조: (한 가지 단점은 참조 구성 요소의 ID를 수동으로 설정해야 한다는 것입니다. 즉, manual!!!) 예: btnOne을 중앙에 배치한 후 BtnTwo를 btnOne 아래, 상위 컨테이너 오른쪽에 배치합니다!

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        RelativeLayout rly = new RelativeLayout(this);  
        Button btnOne = new Button(this);  
        btnOne.setText("按钮1");  
        Button btnTwo = new Button(this);  
        btnTwo.setText("按钮2");  
        // 为按钮1设置一个id值  
        btnOne.setId(123);  
        // 设置按钮1的位置,在父容器中居中  
        RelativeLayout.LayoutParams rlp1 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
        rlp1.addRule(RelativeLayout.CENTER_IN_PARENT);  
        // 设置按钮2的位置,在按钮1的下方,并且对齐父容器右面  
        RelativeLayout.LayoutParams rlp2 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
        rlp2.addRule(RelativeLayout.BELOW, 123);  
        rlp2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);  
        // 将组件添加到外部容器中  
        rly.addView(btnTwo, rlp2);  
        rly.addView(btnOne, rlp1);  
        // 设置当前视图加载的View即rly  
        setContentView(rly);  
    }  
}

——4단계:

setContentView() 메소드를 호출하여 레이아웃 객체를 로드합니다! 또한 컨테이너에서 뷰를 제거하려면 컨테이너를 호출하면 됩니다.removeView(제거할 구성 요소);

Runscreenshot:

1.png


3 Java 코드를 동적으로 추가합니다. 컨트롤 또는 xml 레이아웃

우리가 설명한 두 번째 요점은 순수 Java 코드를 사용하여 레이아웃을 로드하는 것입니다. 실제로는 많이 사용되지 않으며 더 동적입니다. 보기 컨트롤을 추가하고 XML 레이아웃을 동적으로 로드하세요!

1) 동적으로 View를 추가하는 Java 코드

구성 요소를 동적으로 추가하는 방법에는 두 가지가 있습니다. 차이점은 먼저 setContentView(R.layout.activity_main)을 수행해야 하는지 여부에 있습니다. 다음은 버튼 추가를 위한 두 가지 쓰기 방법을 보여줍니다.

먼저 레이아웃 파일 작성: activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/RelativeLayout1"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent" >  
  
    <TextView   
        android:id="@+id/txtTitle"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="我是xml文件加载的布局"/>  
</RelativeLayout>

첫 번째 방법은 레이아웃 파일을 로드하는 데 setContentView()가 필요하지 않습니다.

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        Button btnOne = new Button(this);  
        btnOne.setText("我是动态添加的按钮");  
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(    
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    
        lp2.addRule(RelativeLayout.CENTER_IN_PARENT);    
        LayoutInflater inflater = LayoutInflater.from(this);  
        RelativeLayout rly = (RelativeLayout) inflater.inflate(  
                R.layout.activity_main, null)  
                .findViewById(R.id.RelativeLayout1);  
        rly.addView(btnOne,lp2);  
        setContentView(rly);  
    }  
}

두 번째 유형은 레이아웃 파일을 먼저 로드하기 위해 setContentView()가 필요하지 않습니다.

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        Button btnOne = new Button(this);  
        btnOne.setText("我是动态添加的按钮");  
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(    
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    
        lp2.addRule(RelativeLayout.CENTER_IN_PARENT);    
        RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);  
        rly.addView(btnOne,lp2);  
    }  
}

분석 요약:

코드는 매우 간단합니다. 버튼을 만든 후 버튼의 크기를 설정하는 LayoutParams 개체를 만들었습니다. AddRule() 메소드를 통해 버튼 위치를 설정합니다!

첫 번째 메소드: LayoutInflate의 inflate() 메소드를 통해 Activity_main 레이아웃을 로드하고 외부 컨테이너를 얻습니다. 그런 다음 addView가 컨테이너에 버튼을 추가하고 마지막으로 setContentView();

두 번째 메서드: setContetView() 메서드를 통해 레이아웃을 로드했기 때문에 이번에는 다음을 전달할 수 있습니다. findViewById는 외부 컨테이너를 찾은 다음 addView, 그리고 마지막으로 setContentView()!

또한 setContentView()에 의해 설정된 뷰 노드는 전체 XML의 루트 노드입니다!


2) Java 코드는 xml 레이아웃을 동적으로 로드합니다

다음으로 바꿔보겠습니다. 이번에는 xml 파일을 로드해보겠습니다. xml 파일을 동적으로 추가해보겠습니다! 먼저 기본 레이아웃 파일과 동적으로 로드된 레이아웃 파일을 기록해 둡니다.

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/RelativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/btnLoad"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="动态加载布局"/></RelativeLayout>

inflate.xml:

<?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"  
    android:id="@+id/ly_inflate" >  
  
    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="我是Java代码加载的布局" />  
  
    <Button  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="我是布局里的一个小按钮" />  
  </LinearLayout>

그런 다음

MainActivity.java로 이동하여 여기에서 xml 레이아웃을 동적으로 로드합니다.

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        //获得LayoutInflater对象;  
        final LayoutInflater inflater = LayoutInflater.from(this);    
        //获得外部容器对象  
        final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);  
        Button btnLoad = (Button) findViewById(R.id.btnLoad);  
        btnLoad.setOnClickListener(new OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                //加载要添加的布局对象  
                LinearLayout ly = (LinearLayout) inflater.inflate(  
                        R.layout.inflate, null, false).findViewById(  
                        R.id.ly_inflate);  
                //设置加载布局的大小与位置  
                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(    
                        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    
                lp.addRule(RelativeLayout.CENTER_IN_PARENT);    
                rly.addView(ly,lp);  
            }  
        });  
    }  
}

실행 중인 스크린샷:

2.gif

코드 분석:

①컨테이너 객체 가져오기:

final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);

②인플레이터 객체를 가져와서 추가된 레이아웃의 xml을 로드하고 가장 바깥쪽 부분을 찾습니다. findViewById를 통해 레이어의 루트 노드

final LayoutInflater inflater = LayoutInflater.from(this);
LinearLayout ly = (LinearLayout) inflater.inflate(R.layout.inflate, null, false)
   .findViewById(R.id.ly_inflate);

3 이 컨테이너의 크기 및 위치 정보 설정:

RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(  
               LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
       lp.addRule(RelativeLayout.CENTER_IN_PARENT);

4 외부 컨테이너에 추가:

rly.addView(ly,lp);


4.LayoutInflater의 inflate() 메소드 소스 code

마지막으로 LayoutInflater의 inflate() 메서드 소스 코드를 제공합니다. 관심이 있으시면 살펴보시면 됩니다~ 실제로는 Pull 분석일 뿐입니다~

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {    
    synchronized (mConstructorArgs) {    
        final AttributeSet attrs = Xml.asAttributeSet(parser);    
        mConstructorArgs[0] = mContext;    
        View result = root;    
        try {    
            int type;    
            while ((type = parser.next()) != XmlPullParser.START_TAG &&    
                    type != XmlPullParser.END_DOCUMENT) {    
            }    
            if (type != XmlPullParser.START_TAG) {    
                throw new InflateException(parser.getPositionDescription()    
                        + ": No start tag found!");    
            }    
            final String name = parser.getName();    
            if (TAG_MERGE.equals(name)) {    
                if (root == null || !attachToRoot) {    
                    throw new InflateException("merge can be used only with a valid "    
                            + "ViewGroup root and attachToRoot=true");    
                }    
                rInflate(parser, root, attrs);    
            } else {    
                View temp = createViewFromTag(name, attrs);    
                ViewGroup.LayoutParams params = null;    
                if (root != null) {    
                    params = root.generateLayoutParams(attrs);    
                    if (!attachToRoot) {    
                        temp.setLayoutParams(params);    
                    }    
                }    
                rInflate(parser, temp, attrs);    
                if (root != null && attachToRoot) {    
                    root.addView(temp, params);    
                }    
                if (root == null || !attachToRoot) {    
                    result = temp;    
                }    
            }    
        } catch (XmlPullParserException e) {    
            InflateException ex = new InflateException(e.getMessage());    
            ex.initCause(e);    
            throw ex;    
        } catch (IOException e) {    
            InflateException ex = new InflateException(    
                    parser.getPositionDescription()    
                    + ": " + e.getMessage());    
            ex.initCause(e);    
            throw ex;    
        }    
        return result;    
    }    
}

이 섹션 요약:

이 섹션에서는 Android의 LayoutInflater(레이아웃 서비스)와 뷰 및 컨트롤의 동적 로드에 대해 설명합니다. 관련된 내용은 컨트롤을 처음 접하는 친구들에게 도움이 될 거라 믿습니다~알겠습니다. 감사합니다~

3.gif