How to inflate a ViewStub using ViewBinding in Android
C

3

11

As Kotlin Synthetics is deprecated, we are migrating to ViewBinding.

I have tried a lot of googling and reading documentation on ViewStub, ViewBinding and have implemented ViewBinding for Fragments Activities, include, merge tags however I could not find any way to inflate the ViewStub using ViewBinding.

 <ViewStub
            android:id="@+id/viewStubLayout"
            tools:layout="@layout/view_demo_layout" />

Please ignore the width and height attributes for this they were added as a style and have been removed from this snippet.

Can you please share how to inflate this view with another xml layout dynamically using ViewBinding.

Even in the ViewStub.java file, the class level comments state that,

The preferred way to perform the inflation of the layout resource is the following:

ViewStub stub = findViewById(R.id.stub);
View inflated = stub.inflate(); 

Does this mean that, I have to keep using R.layout.xxx_xx to inflate the viewstub. Can't I use the binding object for that particular xml file to inflate the view ?

Cordi answered 19/3, 2021 at 7:0 Comment(4)
Inflation will be like that only stub.inflate() . If you want binding object the you can get it by DataBindingUtil.bind(inflated).Fryer
@ADM The question is that instead of using R.layout.stub here in this line : ViewStub stub = findViewById(R.id. view_demo_layout); Can I use the binding class that would be generated : ViewDemoLayoutBinding ?Cordi
also, what is DataBindingUtil ? I a not using DataBinding. I am using ViewBinding.Cordi
Its the same thing you can call ViewDemoLayoutBinding.bind() on your binding class instead of DataBindingUtil .Fryer
H
13

I wrote about ViewBinding when it was in Beta. I covered every case except ViewStub. ViewStub case is fairly similar to the case of <Include> in my linked article. What you have to do is call bind() function of your ViewStub layout and pass the root where you added ViewStub. Remember to call bind() in setOnInflateListener.

class MainFragment : Fragment() {
private var binding: FragmentMainBinding by autoCleared()
private var stubBinding: StubBinding by autoCleared()

  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
      binding = FragmentMainBinding.inflate(inflater, container, false)
      binding.stub.setOnInflateListener { _, inflateId -> stubBinding = StubBinding.bind(inflateId) }
      return binding.root
  }

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
      super.onViewCreated(view, savedInstanceState)
      binding.stub.inflate()
      stubBinding.tvTestMe.text = "Hurray"
   }
}
Hypoglycemia answered 19/3, 2021 at 9:46 Comment(7)
Where does "by autoCleared" come from?Talon
@Talon You can find it on Google's Github browser sampleHypoglycemia
Thanks for the answer. Question: What about two-way-databinding in viewstub? How does that work. Normal "@={text}" is not workingTalon
@Talon I don't use data-binding... So I can't answer that. Sorry!Hypoglycemia
Isn't the reason for stubs to dynamically be able to switch layouts, for example if you want to decide which layout to inflate into the stub based on a typed variable? The above approach locks you in due to the type of the stubBinding variable having to match the layout I inflate, doesn't it? Is there a way to not depend on the included layout directly (assuming the IDs in both possible layouts are the same) and to be able to access the included layout through a stubBinding variable that supports two layouts?Cracking
@Somesh Kumar I am trying to set up ViewBinding with a ViewStub, using Android code here: #77975860 I don't know Kotlin so I would appreciate any insights or ideas you have for conversion using Android.Copperas
But what about if I use activity instead of fragmentCosy
Q
4

One small correction in @Somesh's answer

The inflated view which is passed to the StubBinding is wrong. We should actually pass the view which we receive from the onInflate listener

class MainFragment : Fragment() {
private var binding: FragmentMainBinding by autoCleared()
private var stubBinding: StubBinding by autoCleared()

  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
      binding = FragmentMainBinding.inflate(inflater, container, false)
      binding.stub.setOnInflateListener { _, inflated -> stubBinding = StubBinding.bind(inflated) }
      return binding.root
  }

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
      super.onViewCreated(view, savedInstanceState)
      binding.stub.inflate()
      stubBinding.tvTestMe.text = "Hurray"
   }
}
Quasi answered 7/6, 2021 at 15:14 Comment(1)
Original answer has been edited to fix thisConstantinople
R
-1

It can be done via 2 simple lines

binding.viewStub.layoutResource = R.layout.layoutId
binding.viewStub.inflate()
Rausch answered 28/6, 2021 at 8:10 Comment(1)
This answer is missing an important line of code: Binding of the stub. stubBinding = StubBinding.bind(inflated) where inflated is the view returned from line 2.Inconceivable

© 2022 - 2024 — McMap. All rights reserved.