I've written the test, testing if the recycler view is displayed (id: comments_view), but it always fails and I've no idea why. When I'm checking for layout (id: cm), the test passes.
I have the following fragment code:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="post"
type="com.example.kotlinpostapi.apiObjects.Post" />
<variable
name="comments"
type="java.util.List" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".views.MainActivity"
android:id="#+id/cm">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/comments_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
The test code (I'm navigating to the fragment from another one):
#RunWith(AndroidJUnit4::class)
class CommentsListTest{
#get: Rule
val activityScenario = ActivityScenarioRule(MainActivity::class.java)
#Test
fun testCommentsAreDisplayed() {
onView(withId(R.id.posts_view)).perform(actionOnItemAtPosition<PostAdapter.PostsViewHolder>(0, MyMatchers.clickChildView(R.id.show_comments_button)))
//it fails
onView(withId(R.id.comments_view)).check(matches(isDisplayed()))
//it passes
onView(withId(R.id.cm)).check(matches(isDisplayed()))
}
}
How is it possible, and how can I test my recycler view?
The height of the RecyclerView is set to wrap_content and if the element is not visible at least 90% the test fails.
What you could do is to check one of the RecyclerView children.
I firstly declare the following method:
fun nthChildOf(parentMatcher: Matcher<View?>, childPosition: Int): Matcher<View?>? {
return object : TypeSafeMatcher<View>() {
override fun describeTo(description: Description) {
description.appendText("with $childPosition child view of type parentMatcher")
}
override fun matchesSafely(view: View): Boolean {
if (view.parent !is ViewGroup) {
return parentMatcher.matches(view.parent)
}
val group = view.parent as ViewGroup
return parentMatcher.matches(view.parent) && group.getChildAt(childPosition) == view
}
}
}
with this you can check whether its first child is displayed:
onView(nthChildOf(withId(R.id.comments_view), 0)).check(matches(isDisplayed()))
And to check one element of its children (recyclerview_element_id for example):
onView(allOf(
withId(R.id.recyclerview_element_id),
isDescendantOfA(
nthChildOf(withId(R.id.comments_view), 0))
)).check(matches(isDisplayed()))
Another thing you could try if your RecyclerView expands to the available space of the screen is to change the layout of the RecyclerView to have all the constraints set and with and height to 0dp:
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/comments_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
I have it this way and doing:
onView(withId(R.id.myRecyclerviewId)).check(matches(isDisplayed()))
works for me.
Related
I have a problem:
I have a TextView whose content is constantly changing via LiveData. This looks all right when the animation isn't executing, but when the MotionLayout starts executing, my text gets blocked a little bit.
And the constraints of my TextView and Button are packed.
activity:
class ErrorActivity : AppCompatActivity() {
private val mViewModel by viewModels<ErrorViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
DataBindingUtil.setContentView<ActivityErrorBinding>(this, R.layout.activity_error).apply {
lifecycleOwner = this#ErrorActivity
viewModel = mViewModel
}
}
fun startStopAnim(v: View) {
mViewModel.anim()
}
}
activity layout:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:binding="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.test.test.ErrorViewModel" />
</data>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="#xml/scene"
binding:anim="#{viewModel.mAnim}">
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{#string/test(viewModel.mCountDown)}"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="#+id/btn"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="#string/test" />
<Button
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/tv"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/anim"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="startStopAnim"
android:text="startOrStop"
android:textAllCaps="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.motion.widget.MotionLayout>
</layout>
viewModel:
class ErrorViewModel : ViewModel() {
private val _countDown: MutableLiveData<String> = MutableLiveData()
val mCountDown: LiveData<String> = _countDown
private val _anim: MutableLiveData<Boolean> = MutableLiveData()
val mAnim: LiveData<Boolean> = _anim
private var count = 0
private var state = false
init {
viewModelScope.launch(Dispatchers.IO) {
while (true) {
delay(1000)
_countDown.postValue(count++.toString())
}
}
}
fun anim() {
state = !state
_anim.value = state
}
}
#BindingAdapter("anim")
fun anim(layout: MotionLayout, play: Boolean?) {
play?.let {
if (it) {
layout.transitionToEnd()
} else {
layout.transitionToStart()
}
}
}
motionScene:
For simplicity, Scene has only one duration
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="#+id/end"
app:constraintSetStart="#+id/start"
app:duration="2000" />
</MotionScene>
gif
As you can see in the gif, when there is no click, everything works fine for the numbers, but when I click the button, a 2 second animation starts, during which time my text doesn't display properly.
Of course, this is just a demo example. In a real scene, not only the text is not displayed completely, but even the TextView And ImageView are misplaced, and once the animation is executed, it cannot be recovered.
Can someone help me...
Actually in a real scene, the parent layout (B) of the problematic TextView (A) would perform a displacement animation. As long as this animation is executed once, the constraint relationship of TextView A will definitely have problems and cannot be restored (onResume can be restored after onPause is currently found)
By design during animation MotionLayout does not honor requestLayout.
Because in the majority of applications it is not needed and would have a significant impact on performance.
To enable it in the transition add
<Transition ... motion:layoutDuringTransition="honorRequest" \>
I am displaying a list of countries along with their flags in recylerview
The 1st element does not have a image and uses a default image which is visible on launch of page
But when I scroll and come back to it the image gets changed to some random from the list which should not happen
This is my adapter
class CountryAdapter(private val list: MutableList<Data?>?) :
RecyclerView.Adapter<CountryAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ElementCountryBinding.inflate(inflater)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val country: Data? = list?.get(position)
if (country != null) {
holder.bind(country)
}
holder.itemView.setOnClickListener {
}
}
override fun getItemCount(): Int = list!!.size
inner class ViewHolder(val binding: ElementCountryBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(country: Data) {
binding.data = country
if (country.filePath != null)
Glide.with(binding.root.context)
.load(country.filePath!!.trim()).into(binding.ivFlag)
}
}
}
This is the xml layout
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="data"
type="com.mountmeru.model.Data" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:id="#+id/main_cardview"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_marginBottom="5dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/iv_flag"
android:layout_width="100dp"
android:layout_height="70dp"
android:layout_marginStart="10dp"
android:adjustViewBounds="true"
android:src="#drawable/ic_share"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvCountryName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="#{data.countryName}"
app:layout_constraintBottom_toBottomOf="#+id/iv_flag"
app:layout_constraintLeft_toRightOf="#+id/iv_flag"
app:layout_constraintTop_toTopOf="#+id/iv_flag" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
< /RelativeLayout>
</layout>
screenshot
So the default image you specified in your XML layout is the ic_share, this means that when onBindViewHolder is called, the image gets substituted by:
.load(country.filePath!!.trim()).into(binding.ivFlag)
However, you never specified that at position 0, the icon must be ic_share, so because of RecyclerView's nature, when you scroll downwards and upwards and the first itemHolder is created (again) it uses a recycled view from further down, and as you're not setting ic_share to iv_flag at position 0 it just uses the recycled view image.
If you just add a line of code like #ADM suggested in your bind method like this:
if(adapterPosition==0){
binding.ivFlag.setImageResource(R.drawable.ic_share)
}
With the ic_share, I think that should make it work
That's normal due to the recycling mechanism of views in RV/LV. To avoid that set it to null
if (country.filePath != null)
Glide.with(binding.root.context)
.load(country.filePath!!.trim()).into(binding.ivFlag)
else
binding.ivFlag.setImageDrawable(null)
assuming ivFlag is an ImageView, or a default/placeholder if you have it
This is happening because you never set ic_share during bind View.
inner class ViewHolder(val binding: ElementCountryBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(country: Data) {
binding.data = country
if(adapterPosition==0){
binding.ivFlag.setImageResource(R.drawable.binding.ivFlag)
}else {
if (country.filePath != null)
Glide.with(binding.root.context)
.load(country.filePath!!.trim()).into(binding.ivFlag)
}
}
}
Having the function getItemViewType also solves the problem
override fun getItemViewType(position: Int): Int {
return position
}
I'm using the latest Nav Component (2.2.0-alpha01) in my project, and am presented with an issue I can't seem to resolve.
I have a splash animation - nothing serious, a custom background stretching to the whole screen, and a logo in the very middle, using ConstraintLayout. During the initial sync, I animate a custom animated VectorDrawable (let's call it #drawable/logo_animated), which uses the common #drawable/logo as a source, and applies animations to its groups.
To time the animation right, I created the following helper function:
fun ImageView.setRepeatingAnimatedVector(
#DrawableRes animationRes: Int,
delayMs: Long = 0,
startDelayMs: Long = 0,
shouldRunOptional: () -> Boolean = { false },
optionalRunnable: () -> Unit = {}
) {
val anim = AnimatedVectorDrawableCompat.create(context, animationRes)?.apply {
registerAnimationCallback(object : Animatable2Compat.AnimationCallback() {
override fun onAnimationEnd(drawable: Drawable?) {
this#setRepeatingAnimatedVector.postDelayed({ if (shouldRunOptional()) optionalRunnable() else start() }, delayMs)
}
})
}
setImageDrawable(anim)
postDelayed({ anim?.start() }, startDelayMs)
}
It takes an AnimatedVectorDrawable as an input, and applies it to the ImageView. Upon finishing the animation cycle, a check in the form of a lambda (shouldRunOptional) is ran. If it returns true, the optionalRunnable lambda is launched, otherwise it repeats the animation.
With this, I can wait for the ViewModel to finish syncing, and then await the end of the animation to move between fragments without any weirdness. The animation itself is short (~900ms), so at most the user will be delayed by a second.
I also use a custom NavigationManager composition for navigation. The Manager itself is an interface (INavigationManager) of generic calls (such as splashToLanding() or openDetail(id: UUID)) that gets injected into ViewModels, with an extra interface taking care of the NavComponent specific bits:
IFragmentNavigator.kt
interface IFragmentNavigator {
val command: SingleLiveEvent<NavigationCommand>
var splashLandingExtras: Navigator.Extras?
fun setSplashLandingTransition(extras: Navigator.Extras) {
splashLandingExtras = extras
}
fun back() {
navigate(NavigationCommand.Back)
}
fun navigate(direction: NavDirections) {
navigate(NavigationCommand.To(direction))
}
fun navigate(navCommand: NavigationCommand) {
command.postValue(navCommand)
}
}
The implementation just takes care of property initializations, and then later on used in the following manner:
class FragmentNavigationManager:
INavigationManager, IFragmentNavigator by FragmentNavigator() { [...] }
The command property of this interface is then later used in the Fragments, via Observers:
open val navigationObserver = Observer<NavigationCommand> {
when(it) {
is NavigationCommand.To -> findNavController().navigate(it.directions)
is NavigationCommand.Back -> findNavController().popBackStack()
is NavigationCommand.BackTo -> findNavController().popBackStack(it.destinationId, false)
is NavigationCommand.ToRoot -> TODO()
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
navigator.command.observe(this, navigationObserver)
}
The Directions instance created in the FragmentNavigationManager is used by the NavController directly. I made sure to add the FragmentNavigator's Extras field to the actual navigation call:
override fun splashToLanding() {
navigate(
NavigationCommand.To(
SplashFragmentDirections.actionSplashFragmentToLandingFragment(),
null, null, splashLandingExtras
)
)
}
And of course in the SplashFragment, I assign the appropriate view to the transition name for splashLandingExtras:
navigator.splashLandingExtras = FragmentNavigatorExtras(binding.logo to "logo")
In the LandingFragment's onCreate method, I do set up enter and exit animations:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
TransitionInflater.from(context).inflateTransition(android.R.transition.move).let {transition ->
sharedElementEnterTransition = transition
sharedElementReturnTransition = transition
}
}
The layouts are the following:
splash.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.felcana.app.viewmodel.SplashViewModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<include layout="#layout/background" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<ImageView
android:id="#+id/logo"
style="?attr/logoStyle"
android:transitionName="logo"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
landing.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.my.app.viewmodel.LandingViewModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<include layout="#layout/background" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<ImageView
android:id="#+id/logo"
style="?attr/logoStyle"
android:layout_marginBottom="24dp"
android:transitionName="logo"
app:layout_constraintBottom_toTopOf="#id/button_register"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="#+id/button_register"
style="?attr/flatWhiteButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="8dp"
android:onClick="#{() -> viewModel.goToRegister()}"
android:text="#string/button_register"
app:layout_constraintBottom_toTopOf="#id/button_login"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="#+id/button_login"
style="?attr/borderlessWhiteButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:onClick="#{() -> viewModel.goToLogin()}"
android:text="#string/button_login"
app:layout_constraintBottom_toTopOf="#id/disclaimer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="#+id/disclaimer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="32dp"
android:maxLines="2"
android:textAlignment="center"
android:textColor="#color/app_white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="#tools:sample/lorem/random" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
For some reason, the animation does not play at all - the ImageView just jumps without any sort of transition to the new position.
What's going wrong here? According to the documentation, this should be working. I did try going back to more stable versions of the NavComponent library, to no avail.
Have you tried postponing the enter transition inside LandingFragment::onViewCreated and manually setting the transition name to the view?
Something like this:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// Pause the enter transition
postponeEnterTransition()
// Manually apply the transitionName
logo.transitionName = "logo"
// Resume the transition
startPostponedEnterTransition()
super.onViewCreated(view, savedInstanceState)
}
I have following HorizontalScrollView which I add items to it programmatically:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="vm"
type="com.sample.android.tmdb.ui.detail.MovieDetailViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:visibleGone="#{vm.isTrailersVisible}">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/trailers"
android:textAppearance="#style/TextAppearance.AppCompat.Title" />
<HorizontalScrollView
android:id="#+id/trailer_scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:items="#{vm.trailers}" />
</HorizontalScrollView>
</LinearLayout>
</layout>
And here I add items to it :
#JvmStatic
#BindingAdapter("items")
fun addItems(linearLayout: LinearLayout, trailers: List<Video>) {
linearLayout.removeAllViews()
val context = linearLayout.context
for (trailer in trailers) {
val thumbContainer = context.layoutInflater.inflate(R.layout.video, linearLayout, false)
val thumbView = thumbContainer.findViewById<ImageView>(R.id.video_thumb)
thumbView.apply {
setOnClickListener {
val playVideoIntent = Intent(Intent.ACTION_VIEW, Uri.parse(Video.getUrl(trailer)))
context.startActivity(playVideoIntent)
}
}
linearLayout.addView(thumbContainer)
}
}
Now I want to add a Espresso test for it. I want to scroll HorizontalScrollView and click on third item. Until now I wrote following test:
#Test
fun shouldBeAbleToDisplayTrailer() {
onView(withId(R.id.list)).perform(RecyclerViewActions
.actionOnItemAtPosition<MovieViewHolder>(8, click()))
onView(withId(R.id.trailer_scroll_view)).perform(nestedScrollTo()).check(matches(isDisplayed()))
// intended(Matcher<Intent> matcher) asserts the given matcher matches one and only one
// intent sent by the application.
//intended(allOf(hasAction(Intent.ACTION_VIEW)))
}
But I do not know, how to scroll HorizontalScrollView. Can you please help?
The answer is just two clicks away:
Check scrollTo() View Action implementation:
public static ViewAction scrollTo() {
return actionWithAssertions(new ScrollToAction());
}
Check ScrollToAction() implementation:
/** Enables scrolling to the given view. View must be a descendant of a ScrollView or ListView. */
The view should fulfil below constraints to apply ScrollToAction() to it. I agree that ScrollToAction() description can be improved a bit:
withEffectiveVisibility(Visibility.VISIBLE),
isDescendantOfA(
anyOf(
isAssignableFrom(ScrollView.class),
isAssignableFrom(HorizontalScrollView.class),
isAssignableFrom(ListView.class))));
And the answer is - use ViewActions.scrollTo() to scroll HorizontalScrollView.
I'm trying to create a simple example with databinding and BindingAdapters in order to show/hide a ProgressBar depending on TextView if it's empty or not. Below you can see my code. What I'm doing wrong?
loading_state.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="textString"
type="String"/>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:visibleGone="#{textString==null}">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{textString}"/>
</android.support.constraint.ConstraintLayout>
</layout>
My BindingAdapter
object BindingAdapters {
#JvmStatic
#BindingAdapter("visibleGone")
fun showHide(view: View, visible: Boolean){
view.visibility = if (visible) View.VISIBLE else View.GONE
}
}
I include the layout in my second fragment in order to check the textview text
<include layout="#layout/loading_state"
app:textString="#{textView2.text.toString()}"/>
and also in my SecondFramgent class I take the value from MainFragment class (I'm using the new Navigation component)
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val txtFromMain = SecondFragmentArgs.fromBundle(arguments)
textView2.text = txtFromMain.txtFromMain
}
What am I missing?
Thank you very much.
For those facing the same issue you can find my solutions matches in my case below:
I had to change my BindingAdapter.
#BindingAdapter("visibleGone")
fun showHide(view: View, visible: String){
view.visibility = if (visible.isEmpty()) View.VISIBLE else View.GONE
}
You did not set two-way databinding for TV, thus string is not getting updated inside databinding
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{textString}"/>
Change android:text="#{textString}" to android:text="#={textString}"
This is first look of the problem, does it help?