-2

I created a customview that named PinView extended from RelativeLayout. In constructors, i call my init() method and it inflates a view from a layout.

inflate(getContext(), R.layout.layout_pin_view, this);

After this inflate flow, I need to add my other views(Imageview) in this inflated view by requesting addView(). And throws:

catch (NoSuchMethodException e) {
            InflateException ie = new InflateException(attrs.getPositionDescription()
                    + ": Error inflating class "
                    + (prefix != null ? (prefix + name) : name));
            ie.initCause(e);
            throw ie; 

I can inflate successly with:

mLlPins.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                mLlPins.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                ....
                ....
                addView(...)



            }
        }); 

Do you have an idea why we cant create a dynamic view with inflating in synchronously?

My code parts:

private void init() {
    View view = inflate(getContext(), R.layout.layout_pin_view, this);
    mEtPin = (PinEditText) view.findViewById(R.id.etPin);
    mLlPins = (LinearLayout) view.findViewById(R.id.llPins);
    mEtPin.setVisibility(View.VISIBLE);
    mEtPin.setFilters(new InputFilter[]{new InputFilter.LengthFilter(mMaxLength)});
    mEtPin.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return false;
        }
    });
    mEtPin.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            if (mImageViews != null) {
                for (int i = 0; i < mImageViews.length; i++)
                    mImageViews[i].setEnabled(i < s.length());
                if (s.length() == mMaxLength) {
                    InputMethodManager imm = (InputMethodManager) mEtPin.getContext().getSystemService(
                            Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(mEtPin.getWindowToken(), 0);
                }
            }
        }
    });
    mLlPins.setClickable(false);
    mEtPin.setText(mEtPin.getText());

    mEtPin.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            if (mImageViews == null) return;
            for (int i = 0; i < mMaxLength; i++) {
                if (mImageViews[i] != null) {
                    if (i < s.length()) {
                        mImageViews[i].setImageAlpha(255);
                        continue;
                    }
                }
                mImageViews[i].setImageAlpha(0);
            }

        }
    });

    setMaxLength(4);
}
private void setMaxLength(int maxLength) {
    LayoutInflater inflater = LayoutInflater.from(mLlPins.getContext());
    mMaxLength = maxLength;
    mEtPin.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});
    mImageViews = new ImageView[maxLength];
    mLlPins.removeAllViews();
    int totalContentLenght = mLlPins.getMeasuredWidth() - dpToPx((maxLength - 1) * mMargin);
    int itemWidthHeight = totalContentLenght / maxLength;
    int itemMargin = dpToPx(mMargin / 2);
    int itemPadding = (int) (itemWidthHeight * srcRatio);
    for (int i = 0; i < maxLength; i++) {
        mImageViews[i] = (ImageView) inflater.inflate(mPinImage, null);
        mImageViews[i].setEnabled(false);
        mImageViews[i].setPadding(itemPadding, itemPadding, itemPadding, itemPadding);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(itemWidthHeight, itemWidthHeight);
        if (i == 0) {
            params.setMargins(0, 0, itemMargin, 0);
        } else if (i < maxLength - 1) {
            params.setMargins(itemMargin, 0, itemMargin, 0);
        } else {
            params.setMargins(itemMargin, 0, 0, 0);

        }
        mImageViews[i].setImageAlpha(0);
        mLlPins.addView(mImageViews[i], params);

    }

}
atasoyh
  • 3,045
  • 6
  • 31
  • 57
  • 1
    Please post your constructors and `init()` method, and the stack trace from the caught `Exception`. – Mike M. Aug 04 '16 at 07:49
  • 1
    Ahh! It is my fault. I found the problem while I trying to get logs. In Activity, after oncreate, this activity is closed by some controls. If i debug this process, it throws error as I wrote. I need to close this question. And also I need to use globallayoutlistener for getting view's sizes:) – atasoyh Aug 04 '16 at 08:04

1 Answers1

1

In my understanding, you cannot inflate the views because of the parent view (says as container) is not drawn which means all its layout parameters are not settled, when you add a view, your view cannot calculate its own view parameters due to container is not yet initiated. If you want to use the initiate child view method inside the container onCreate method, you may try the following inside your container create method:

containerVariable.post(new Runnable(){
    @Override
    public void run(){
      // initiate your child view and add child view here 
    }
});
S.W.
  • 139
  • 8
  • Could I use it instead of GlobalLayoutListener? Which is more appropriate method ? – atasoyh Aug 04 '16 at 08:08
  • 1
    In my understanding, GlobalLayoutListener is a method provided in standard Android Library and it's more preferred, however, I suggest post method due to GlobalLayoutListener needs to handle with different Android version issue, and post method is some kind of Process Handling ways. – S.W. Aug 04 '16 at 08:11