Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Slider] label is gone with slider #4320

Closed

Conversation

manabu-nakamura
Copy link
Contributor

@manabu-nakamura manabu-nakamura commented Sep 29, 2024

closes #4319
I'm worried about performance:

  private boolean isVisible() {
    if (getVisibility() != VISIBLE) {
      return false;
    }
    for (ViewParent viewParent = getParent(); viewParent instanceof View; viewParent = viewParent.getParent()) {
      if (((View) viewParent).getVisibility() != VISIBLE) {
        return false;
      }
    }
    return true;
  }

@dsn5ft
Copy link
Contributor

dsn5ft commented Sep 30, 2024

Thanks @manabu-nakamura, can you explain what you mean by your comment about performance? What is that code snippet from?

@manabu-nakamura
Copy link
Contributor Author

The isVisible() method is an alternative to the isVisible field (and the onVisibilityAggregated() method). These are what I wrote. The isVisible field (and the onVisibilityAggregated() method) is more lightweight than the isVisible() method, I think.

@@ -354,6 +354,8 @@ abstract class BaseSlider<
private final ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener =
this::updateLabels;

private boolean isVisible = true;
Copy link
Contributor

@dsn5ft dsn5ft Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@manabu-nakamura just wondering about the default value being true here. if the Slider visibility is set to gone or invisible initially (e.g. in the xml layout), will onVisibilityAggregated() be called with false immediately after the view is inflated / created?

if not then maybe in the constructor we could set isVisible = getVisibility() == View.VISIBLE?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just checked locally and onVisibilityAggregated doesn't seem to get called when the Slider itself has android:visibility="invisible" or android:visibility="gone" in the XML layout.

So the isVisible boolean would be incorrect in those cases, which makes me think we should not initialize isVisible to true and instead do isVisible = getVisibility() == View.VISIBLE in the constructor.

Although that doesn't cover the case where the Slider is visible but the parent view is gone. because in that case getVisibility() == View.VISIBLE would return true in the Slider constructor and onVisibilityAggregated doesn't get called after the initial inflation to correct it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much. Following pubiqq's advice, I replaced the isVisible field with the isShown() method. I tried displaying labels in the SliderScrollContainerDemoFragment demo. There seems to be no problem.
https://github.com/material-components/material-components-android/blob/master/catalog/java/io/material/catalog/slider/SliderScrollContainerDemoFragment.java

slider.setLabelBehavior(LabelFormatter.LABEL_VISIBLE);

@pubiqq
Copy link
Contributor

pubiqq commented Oct 1, 2024

It seems I was invited here by mistake, nevertheless I have something to say:

  • You cannot use View#onVisibilityAggregated(boolean) as it's only available from API 24.
  • You don't need to implement the visibility check yourself, use View#isShown().

@manabu-nakamura
Copy link
Contributor Author

Thank you for your great advice!

@dsn5ft
Copy link
Contributor

dsn5ft commented Oct 7, 2024

@manabu-nakamura @pubiqq View#isShown basically does the same thing as the code snippet in the PR description:

so I think the performance concern is still relevant here - since isSliderVisibleOnScreen() / updateLabels() is called on every scroll + global layout change:

@NonNull
private final ViewTreeObserver.OnScrollChangedListener onScrollChangedListener =
this::updateLabels;
@NonNull
private final ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener =
this::updateLabels;

meaning it would walk up the full view hierarchy on every scroll + global layout change.

@pubiqq
Copy link
Contributor

pubiqq commented Oct 8, 2024

The performance loss is negligible (few viewFlags & VISIBILITY_MASK != VISIBLE checks), I don't see any reason to worry about that.

@manabu-nakamura
Copy link
Contributor Author

I don't think there seem to be any performance issues, but I tried rewriting the program.

@@ -354,6 +354,8 @@ abstract class BaseSlider<
private final ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener =
this::updateLabels;

private boolean isVisible = isShown();
Copy link
Contributor

@dsn5ft dsn5ft Oct 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@manabu-nakamura did you test this? I don't think isShown() will really work here since when the view class / object is initially constructed, it is not added to the hierarchy yet. I think the field should be left uninitialized and then you can do isVisible = isShown(); in onAttachedToWindow()?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually I'm thinking we can do isVisible = isShown() in the constructor after the super() call (that way the super class has at least processed the initial setVisibility()), and then also isVisible = isShown() in onAttachedToWindow() to account for the parent hierarchy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was able to run Test8 without any problems in the following cases:

  • BottomAppBar
    • android:visibility="visible"
    • android:visibility="invisible"
    • android:visibility="gone"

https://docs.oracle.com/javase/specs/jls/se23/html/jls-12.html#jls-12.5

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I modified the initialization of isVisible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BottomAppBar? The case I'm referring to is when the parent of the Slider is invisible/gone, isShown() won't work correctly in the constructor because the parent hierarchy is not assigned yet:

https://stackoverflow.com/questions/7099249/using-view-getparent-in-views-constructor

I'll add it to onAttachedToWindow() when importing the PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much. I see.

I was able to run Test8 without any problems in the following cases:

  <com.google.android.material.bottomappbar.BottomAppBar
    android:id="@+id/appBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:fitsSystemWindows="true"
    android:visibility="visible">				<=
    <com.google.android.material.slider.Slider
      android:id="@+id/slider"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:labelBehavior="visible" />
  </com.google.android.material.bottomappbar.BottomAppBar>
  <com.google.android.material.bottomappbar.BottomAppBar
    android:id="@+id/appBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:fitsSystemWindows="true"
    android:visibility="invisible">				<=
    <com.google.android.material.slider.Slider
      android:id="@+id/slider"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:labelBehavior="visible" />
  </com.google.android.material.bottomappbar.BottomAppBar>
  <com.google.android.material.bottomappbar.BottomAppBar
    android:id="@+id/appBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:fitsSystemWindows="true"
    android:visibility="gone">					<=
    <com.google.android.material.slider.Slider
      android:id="@+id/slider"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:labelBehavior="visible" />
  </com.google.android.material.bottomappbar.BottomAppBar>

@pekingme pekingme closed this in 9bf5edd Oct 14, 2024
@manabu-nakamura manabu-nakamura deleted the slider5 branch October 14, 2024 16:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Slider] label is not gone with slider
3 participants