Dynamically added Views not visible

109 views Asked by At

I am trying to add TextViews to a LinearLayout wrapped in a ScrollView during runtime, but the visibility of the TextViews will eventually not display on screen even though their visibility flags are all set to Visible.

myLayout = FindViewById<LinearLayout>(Resource.Id.myScollLayout);

View myView = LayoutInflater.From(this).Inflate(Resource.Layout.my_view, null);
TextView text1 = myView.FindViewById<TextView>(Resource.Id.text1);
TextView text2 = myView.FindViewById<TextView>(Resource.Id.text2);
TextView text3 = myView.FindViewById<TextView>(Resource.Id.text3);
text1.Text = "text 1";
text2.Text = "text 2";
text3.Text = "text 3";
LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WrapContent, LinearLayout.LayoutParams.WrapContent);
myLayout.AddView(myView, p);
myView.Visibility = ViewStates.Visible

xml layout

<ScrollView
    android:layout_width="match_parent"
    android:padding="8dp"
    android:layout_marginBottom="16dp"
    android:id="@+id/myScrollView"
    android:layout_height="wrap_content">
    <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginLeft="8dp"
      android:layout_marginRight="8dp"
      android:visibility="visible"
      android:id="@+id/myScrollLayout"
      android:orientation="vertical">
    </LinearLayout>
</ScrollView>

I say eventually because at times the views in the above code display as expected, but eventually on subsequent executions of the code that inflates and adds the views, the views that are added to the inflated layout are not visible on screen. If I check the visbility of all child views, they all say Visible, but on screen they would seem to be displaying as Invisible since there is still space taken up inside the scroll layout, but is blank.

I've referenced a number of other articles that discuss using the following:

  • View.Invalidate()
  • View.RequestLayout()
  • View.Post()
  • RunOnUiThread()

but no combination of the above seem to get the views to appear. I have also implemented a function below to try to force all child views of myScrollLayout to be visible, but still has no impact as all views appear as if they are Invisible.

void SetVisibility(View v)
    {
      if (v.GetType() == typeof(LinearLayout))
      {
        var view = (LinearLayout)v;
        if (view.ChildCount == 0)
        {
          ((Activity)view.Context).RunOnUiThread(() => view.Visibility = ViewStates.Visible);
          return;
        }
        else
        {
          ((Activity)view.Context).RunOnUiThread(() => view.Visibility = ViewStates.Visible);
          for (int i = 0; i < view.ChildCount; i++)
          {
            SetVisibility(view.GetChildAt(i));
          }
        }
      }
      else
      {
        ((Activity)v.Context).RunOnUiThread(() => v.Visibility = ViewStates.Visible);
        return;
      }
      
    }

So in general, what would cause a View to not display on screen even though the visibility of the View and it's parent are both set to Visible?

Update: The purpose of myLayout in the above code is to hold a variable number of TextViews that will be shown (Visible) or hidden (Invisible) as needed. When new TextViews need to be shown, the previous ones are removed with View.RemoveAllViews.

Update #2: I tried replacing myLayout which was a LinearLayout to just a TextView and instead of inflating the view as needed, I just set the value of the TextView. I get similar behavior where even though there should be multiple lines of data, the TextView will sometimes only shows the first line. In this case, the surrounding ScrollView is only drawn on screen to fit the first line. I believe the root of the problem is getting the screen to redraw or display views when they are added or changed during runtime.

2

There are 2 answers

5
Liyun Zhang - MSFT On

I can't reproduce your problem. I tested your code in a new blank xamarin.android project and the textview will show.

The activity_main.xml:

<LinearLayout 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"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   
<ScrollView
    android:layout_width="match_parent"
    android:padding="8dp"
    android:layout_marginBottom="16dp"
    android:id="@+id/myScrollView"
    android:layout_height="wrap_content">
    <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginLeft="8dp"
      android:layout_marginRight="8dp"
      android:visibility="visible"
      android:id="@+id/myScollLayout"
      android:orientation="vertical">
    </LinearLayout>
    </ScrollView>
</LinearLayout>

The my_view.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:id="@+id/text2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:id="@+id/text3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

And the code add the text to the textview:

protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);
            var myLayout = FindViewById<LinearLayout>(Resource.Id.myScollLayout);

            View myView = LayoutInflater.From(this).Inflate(Resource.Layout.my_view, null);
            TextView text1 = myView.FindViewById<TextView>(Resource.Id.text1);
            TextView text2 = myView.FindViewById<TextView>(Resource.Id.text2);
            TextView text3 = myView.FindViewById<TextView>(Resource.Id.text3);
            text1.Text = "text 1";
            text2.Text = "text 2";
            text3.Text = "text 3";
            LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WrapContent, LinearLayout.LayoutParams.WrapContent);
            myLayout.AddView(myView, p);
            myView.Visibility = ViewStates.Visible;
        }

The result image:

enter image description here

In addition, I also tried to put the code about add text to the textview into a button's click event. I got the same result.

0
brutal11 On

Unfortunately I was not able to achieve what I wanted with dynamically added views as shown in the original post. The only way I could get this to work reliably was to have a set number of inflated layouts and inflate them all in OnCreate, then set their visibility as needed. Perhaps this may be a clue for anyone who might know what could cause the original issue.