Android databinding and Scene transition

Viewed 890

In new scene there are buttons that are not present in first scene.

When I change to the new scene databinding does not work - I am not able to delegate onClick from new buttons to the ViewModel.

My current logic is:

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    TestViewModel testViewModel = new TestViewModel();

    ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.test_fragment, container, false);
    binding.setVariable(BR.vm, viewModel);
    binding.executePendingBindings();

    return mainView.getRoot();
}


public void changeToSceneB() {
        ViewGroup sceneRoot = (ViewGroup) getView().findViewById(R.id.scene_root);
        Scene loadedScene = Scene.getSceneForLayout(sceneRoot, R.layout.test_scene_b, getContext());
        Transition transition = TransitionInflater.from(context).inflateTransition(R.transition.test_transition);
        TransitionManager.go(loadedScene, transition);
    }
}

This is part of test_fragment XML:

   <FrameLayout
        android:id="@+id/scene_root"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/appBar"
        android:layout_gravity="center_horizontal"
        android:layout_marginLeft="@dimen/activity_margin"
        android:layout_marginRight="@dimen/activity_margin"
        android:layout_marginTop="70dp">

        <include
            layout="@layout/test_scene_a"
            binding:vm="@{vm}"/>

    </FrameLayout>

and this is how does test_scene_b looks like (code changed, I left most intresting part):

<?xml version="1.0" encoding="utf-8"?>

<data>

    <variable
        name="vm"
        type="com.test.test.TestViewModel"/>
</data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="@dimen/dialog_margin"
        android:gravity="bottom"
        android:orientation="vertical">

        <Button
            style="@style/RoundedButtonGrey"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/dialog_margin"
            android:onClick="@{() -> vm.testFirst()}"
            android:text="Test 1"/>

        <Button
            style="@style/RoundedButtonRed"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/activity_margin"
            android:onClick="@{() -> vm.testSecond()}"
            android:text="Test 2"/>
    </LinearLayout>

Could you tell me why databinding does not work?

2 Answers

The reason is: when you setup xml for the second Scene, you not provide binding variable for this scene, so when it is entered it is not contain your view model.

Workaround is:

  1. Inflate TestSceneBBinding
  2. Set view model in this binding
  3. Use Scene(viewGroup1, viewGroup2) constructor to create Scene
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    TestViewModel testViewModel = new TestViewModel();

    ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.test_fragment, container, false);
    binding.setVariable(BR.vm, viewModel);
    binding.executePendingBindings();

    return mainView.getRoot();
}


public void changeToSceneB() {
    ViewGroup sceneRoot = (ViewGroup) getView().findViewById(R.id.scene_root);
    TestSceneBBinding testSceneBBinding = TestSceneBBinding.inflate(layoutInflater, this.root_group, false) 
    newScreenBinding.vm = viewModel

    Scene loadedScene = Scene(sceneRoot, testSceneBBinding.rootGroup);
    Transition transition = TransitionInflater.from(context).inflateTransition(R.transition.test_transition);
    TransitionManager.go(loadedScene, transition);    
}

Hope it'll help :)

In my case I have layout with root_container and 3 scenes (in separate xml files) and I want to use the same ViewModel for all of them. I faced the same problem as you and here how I solved it:

For bind viewModel to all of scenes I call this code in onViewCreated method:

scene1 = Scene.getSceneForLayout(binding.layoutRootContainer, R.layout.fragment_first_scene, requireContext())
scene2 = Scene.getSceneForLayout(binding.layoutRootContainer, R.layout.fragment_second_scene, requireContext())
scene3 = Scene.getSceneForLayout(binding.layoutRootContainer, R.layout.scene_third_scene, requireContext())

scene1.setEnterAction {
    FragmentFirstSceneBinding.bind(binding.layoutRootContainer.getChildAt(0)).apply {
        vm = viewModel
    }
}

scene2.setEnterAction {
    FragmentSecondSceneBinding.bind(binding.layoutRootContainer.getChildAt(0)).apply {
        vm = viewModel
    }
}

scene3.setEnterAction {
    FragmentThirdSceneBinding.bind(binding.layoutRootContainer.getChildAt(0)).apply {
        vm = viewModel
    }
}

scene1.enter()

And in each scene xml file I define viewModel like this:

<data>
        <variable
            name="vm"
            type="com.myproject.projectapp.presentation.MyViewModel" />
    </data>
Related