【问题标题】:View must have a tag视图必须有标签
【发布时间】:2019-11-03 15:27:48
【问题描述】:

我的库模块中有一个抽象的 BaseActivity:

 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Normal method to inflate the layout
        mBinding = DataBindingUtil.setContentView(this, R.layout.base_view_stub_layout);
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
        if (mBinding != null && mBinding.viewStub != null && mBinding.viewStub.getViewStub() != null) {
            mBinding.viewStub.getViewStub().setLayoutResource(getLayoutId());
        }

        if (!hasStubInflated) {
            View inflatedView = mBinding.viewStub.getViewStub().inflate();
            //Abstract method
            onViewStubInflated(inflatedView, savedInstanceState);
            //Normal method to hide progress bar
            onViewStubInflated();
        }
        initControllers();
        handleViews();
        setListeners();
        restoreValues(savedInstanceState);
    }

AppModule 的 MainActivity 扩展了库模块的 BaseActivity,因此获得了一个抽象方法来覆盖:

MainActivity 扩展 BaseActivity

private ActivityMainBinding mBinding;

@Override
    public int getLayoutId() {
        return R.layout.activity_main;
    }

@Override
    public void onViewStubInflated(View inflatedView, Bundle savedInstanceState) {
        if (mBinding == null || mBinding.getRoot() != inflatedView) {
            mBinding = ActivityMainBinding.bind(inflatedView);
        }
    }

当我运行应用程序时,我得到:

 Caused by: java.lang.RuntimeException: view must have a tag
        at com.example.android.emailapp.DataBinderMapperImpl.getDataBinder(DataBinderMapperImpl.java:67)
        at androidx.databinding.MergedDataBinderMapper.getDataBinder(MergedDataBinderMapper.java:74)
        at androidx.databinding.DataBindingUtil.bind(DataBindingUtil.java:199)
        at androidx.databinding.ViewDataBinding.bind(ViewDataBinding.java:693)
        at com.example.android.emailapp.databinding.ActivityMainBinding.bind(ActivityMainBinding.java:99)
        at com.example.android.emailapp.databinding.ActivityMainBinding.bind(ActivityMainBinding.java:87)
        at com.example.android.emailapp.login.MainActivity.onViewStubInflated(MainActivity.java:86)
        at com.library.android.common.ui.baseui.BaseActivity.onCreate(BaseActivity.java:52)

请注意,我在 BaseActivity 和 MainActivity 的 xml 中都有布局标记。

我尝试了this,但没有成功。

mBinding.viewStub.getViewStub().setLayoutResource(getLayoutId()) 是否是 BaseActivity 中的问题,因为它会尝试从 AppModule 获取布局? 如果是那个,怎么解决?

如果您知道答案,请尝试解释为什么会发生这种情况以及解决方案...

已经尝试过

View must have a tag error

What does it mean by view must have a tag error

How to use databinding for viewstub

【问题讨论】:

标签: android data-binding android-databinding android-architecture-components viewstub


【解决方案1】:

如果您使用自定义类作为your_layout.xml 的根视图,那么您必须覆盖视图的所有构造函数

你的班级

class MyCustomView : FrameLayout {
    constructor(context: Context) : super(context){
        ...
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs){
        ...
    }
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
        ...
    }
}

你的布局

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="viewModel" type="......" />
    </data>

    <MyCustomView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </MyCustomView>

</layout>

【讨论】:

    【解决方案2】:

    您还必须使用 &lt;layout&gt;&lt;/layout&gt; 包装 viewStub 的布局,这正是他们所期望的:要么在任何地方使用 DataBinding,要么根本不在任何地方。


    如果您不想在 viewStub 上使用 DataBinding,则需要做额外的工作。

    例如,如果itemData 是我的列表视图的 DataBindingImpl 对象,并且我要膨胀某种 more options overlay-ViewStub,那么我需要自己存储膨胀的视图,并避免访问DataBinding 的 ViewStubProxy

    ViewGroup inflated = (ViewGroup) itemData.someView.getTag();
    if(inflated==null) {
        ViewStub stub = itemData.viewStubProxy.getViewStub();
        if(stub!=null) {
            stub.setOnInflateListener(null);
            inflated = (ViewGroup) stub.inflate();
            // what I need is simply to set onClickListener on all of it's children. (one for-loop inside)
            Utils.setOnClickListenersOneDepth(inflated, onClickListener, 3, null);
            itemData.someView.setTag(inflated);
        }
    }
    if(inflated!=null) {
        // what I need then is to animate the overlay. 
        View mRoot = inflated;
        int width = itemData.getRoot().getWidth();
        mRoot.setAlpha(0);
        mRoot.setTranslationX(width/3);
        mRoot.animate().alpha(1);
        mRoot.animate().translationX(0);
    }
    

    永远不要调用 itemData.viewStubProxy.getViewStub().getRoot().isInflated() 左右,因为我们现在将 inflated 存储在 DataBindingImpl 对象之外。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-12
      • 2011-09-02
      • 2010-11-15
      • 1970-01-01
      • 1970-01-01
      • 2021-02-02
      • 2013-09-06
      相关资源
      最近更新 更多