cashapp / contour

Layouts with lambdas 😎
Apache License 2.0
1.53k stars 50 forks source link

How to handle multiple gone views? #125

Open nonproto opened 3 years ago

nonproto commented 3 years ago

I have a header and chip group that can be visible, or gone. What is the best way to handle this and not have views overlap? It seems that if the view that visible relies on the view that gone it doesn't always evaluate correct.

Here is the sample in the init of the conditional fields. if for example there is no demographic then i hide the text and chips. This seems to work in some scenarios. One that does does not work is if contentType, format, theme are gone. Then the genre text overlaps in the demographic chip.

        demographicText.layoutBy(
            x = leftTo { parent.left() },
            y = topTo { descriptionExpanded.bottom() }
        )
        demographicChips.layoutBy(
            x = matchParentX(),
            y = topTo { demographicText.bottom() - 8.ydip }
        )

        contentTypeText.layoutBy(
            x = leftTo { parent.left() },
            y = topTo { demographicChips.bottom() }
        )
        contentTypeChips.layoutBy(
            x = matchParentX(),
            y = topTo { contentTypeText.bottom() - 8.ydip }
        )
        formatText.layoutBy(
            x = leftTo { parent.left() },
            y = topTo { contentTypeChips.bottom() }
        )
        formatChips.layoutBy(
            x = matchParentX(),
            y = topTo { formatText.bottom() - 8.ydip }
        )
        themeText.layoutBy(
            x = leftTo { parent.left() },
            y = topTo { formatChips.bottom() }
        )
        themeChips.layoutBy(
            x = matchParentX(),
            y = topTo { themeText.bottom() - 8.ydip }
        )
        genreText.layoutBy(
            x = leftTo { parent.left() },
            y = topTo { themeChips.bottom() }
        )
        genreChips.layoutBy(
            x = matchParentX(),
            y = topTo { genreText.bottom() - 8.ydip }
        )
        altTitlesText.layoutBy(
            x = leftTo { parent.left() },
            y = topTo { genreChips.bottom() }
        )
        altTitles.layoutBy(
            x = matchParentX(),
            y = topTo { altTitlesText.bottom() - 12.ydip }
        )
saket commented 3 years ago

I am not sure I understand this correctly. Are your views overlapping when some of them are set to visibility=gone? Can you share screenshots if possible?

nonproto commented 3 years ago

Working image

Samples with issues 1 2 3

to add a little more info the content that is hidden is hidden on the view creation so

val demographicText = TextView(context).apply{
  conditonally.gone()
}

the layoutBys are all in the init

saket commented 3 years ago

Gotcha. Views with a visibility of gone are considered to not have any position, i.e., 0, 0. I think your best bet is to use conditions inside your axis solvers. Here's an example:

view.layoutBy(
  x = if (otherView.isVisible) otherView.bottom() else parent.top(),
  y = ...
)

The other option would be to keep them invisible but then they'll consume space on the screen.

nonproto commented 3 years ago

Only concern i see with the first approach is it get unwieldy with more components. . Maybe would be nice to have a helper function built in where a view can align to the first visible view. (Grant it i can do it myself in code in but I could see this being an issue for others coming from xml used to just doing gone on views and the alignments auto adjusting)

altTitlesText.layoutBy( 
  x = ..   
  y = if(genreChips.isVisible) genreChips.botom() 
        else if(themeChips.isVisible) themeChips.bottom() 
        else if(formatChips.isVisible) formatChips.bottom() 
        else if(contentTypeChips.isVisible) contentTypeChips.bottom() 
        else if(demographicTypeChips.isVisible) demographicTypeChips.bottom() 
        else parent.bottom()
)

suggestion something like below

altTitlesText.layoutBy( 
  x = ..   
  y = alignBottomFirstVisible(genreChips, themeChips, formatChips, contentTypeChips, demographicChips, parent.bottom)
)