LayoutInflater 날치기, 사용자 정의 속성 교묘 한 해석

최근 에 비교적 특별한 수요 가 있 습 니 다. 바로 모든 View 에 특수 속성 을 추가 하여 XML 에 값 을 부여 할 수 있 습 니 다 (예 를 들 어 tag = "https://static.byr.cn/files/imgupload/2011-07-22-00-24-26.jpg"), View 를 만 들 때 속성 에 따라 동작 을 합 니 다. 예 를 들 어 URL 을 불 러 오 는 등 입 니 다.
이 수 요 는 제한 되 어 있 습 니 다. 1. 일반적인 구조 이 기 를 원 하기 때문에 ImageView, 각종 Layout, 사용자 정의 View 등 다양한 View 를 사용 할 수 있 습 니 다. 따라서 하나의 단독 View 를 계승 할 수 없습니다. 2. 기 존 코드 를 최대한 수정 하지 않 고 사용자 에 게 투명 합 니 다.
문제 의 가장 어 려 운 점 은 적절 한 착안점 이 없어 서 속성 을 읽 고 응용 하 는 것 입 니 다. 나중에 비교적 tricky 방식 으로 이 문 제 를 해결 하 였 습 니 다.
1. Layout Inflater 에 onCreateView 방법 이 있 음 을 알 고 있 습 니 다. 이 방법 은 Public 에서 복사 할 수 있 고 xml 를 읽 고 얻 은 여러 속성 값 을 얻 을 수 있 습 니 다. 따라서 이상 적 인 접근 점 입 니 다.
한 마디 로 Layout Inflater 는 setFactory 와 같은 방식 으로 View 의 생산 을 맞 출 수 있 지만 여기 서 는 적합 하지 않다. 왜냐하면 우 리 는 View 가 어떻게 구축 되 었 는 지 주목 하고 싶 지 않 고 View 가 구 축 된 후에 추가 작업 을 하고 싶 을 뿐이다.
따라서 시스템 의 Layout Infalter 를 교체 할 수 있 기 를 바 랍 니 다.
2. Layout Inflater 의 일상 사용 방식 은 주로 LayoutInfater.from(context) 또는 Activit#getLayoutInflater 등 이 고 마지막 호출 까지 context.getSystemService(LAYOUT_INFLATER) 올 라 옵 니 다.
// LayoutInflater.java
public static LayoutInflater from(Context context) {
        LayoutInflater LayoutInflater =
                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if (LayoutInflater == null) {
            throw new AssertionError("LayoutInflater not found.");
        }
        return LayoutInflater;
    }

시스템 의 '정품' Layout Inflate 는 Phone Layout Inflater 를 사용 합 니 다.
//ContextImpl.java
   @Override
    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }
//SystemServiceRegistry
  registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
                new CachedServiceFetcher() {
            @Override
            public LayoutInflater createService(ContextImpl ctx) {
                return new PhoneLayoutInflater(ctx.getOuterContext());
            }});

저 희 는 Activity 에서 getSystemService 를 다시 쓰 면 Layout Inflater 로 바 꿀 수 있 습 니 다.
public class MainActivity extends Activity {
    LayoutInflater layoutInflater;

    @Override
    public Object getSystemService(String name) {
        if (name.equals(LAYOUT_INFLATER_SERVICE)) {
            if (layoutInflater == null) {
                LayoutInflater origin = (LayoutInflater) super.getSystemService(name);
                //     ni
                layoutInflater = new PPLayoutInflater(origin, this);
            }
            return layoutInflater;
        }
        return super.getSystemService(name);
    }

    @Override
    public LayoutInflater getLayoutInflater() {
        return layoutInflater;
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
  • 사용자 정의 InflaterLayout 의 실현 은 PhoneLayoutInflater 핵심 코드 를 참고 하 였 습 니 다.
  • @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
            Log.e("shitshit", "【" + this.getClass().getSimpleName() + "】   onCreateView() called with: " + "name = [" + name + "], attrs = [" + attrs + "]");
            for (String prefix : sClassPrefixList) {
                try {
                    //                     
                    View view = createView(name, prefix, attrs);
                    if (view != null) {
                        //do custom here...  ImageView     
                        if(view instanceof ImageView) {
    
    
                            if (attrs != null) {
    
                                for (int i = 0; i < attrs.getAttributeCount(); i++) {
                                    String attributeName = attrs.getAttributeName(i);
                                    String attributeValue = attrs.getAttributeValue(i);
                                    //   View     xml        
                                    processAttrs(attributeName, attributeValue, view);
                                }
                            }
    
                        }
                        return view;
                    }
                } catch (ClassNotFoundException e) {
                    // In this case we want to let the base class take a crack
                    // at it.
                }
            }
    
            return super.onCreateView(name, attrs);
        }

    간단 한 processAtts 의 밤:
     public void processAttrs(String attrName, String attrValue, View view){
            if(attrName.equals("tag")){
                view.setBackgroundColor(Color.parseColor(attrValue));
            }
        }

    본문 전체 코드 가 git 에 업로드 되 었 습 니 다.https://github.com/BFridge/CustomLayoutInflater
    사실 SystemService 를 교체 하 는 유사 한 작은 tricky 에 대해 서도 높 은 사람들 이 전문 적 으로 연구 한 적 이 있다.https://github.com/square/mortar

    좋은 웹페이지 즐겨찾기