Luke Jones
Luke Jones

Reputation: 11

Jetpack Compose - Is it possible for content to be visible outside of its bounding box

I have a design where there is an ever present, partially transparent, top bar and then content.

The content needs to be able to scroll, and upon scrolling needs to be visible below the top bar (hence it being partially visible)

The app also needs to be navigable via handset. The easiest way to make content always align when navigating is using a scaffold. Having got it working when the content scrolls up it disappears, it appears to be as the contents bounding box is top -> bottom of the top bar & bottom -> bottom of the page.

it feels like There should be a modifier that means the content, even once it scrolls past the top of the box, can be visible as its still on screen, just its parent has ended.

I've written a very simple test app to show the issue. Which should be easily runnable and demonstrates the problem i am seeing.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApplicationTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                ) {
                    var contentFocusRequester = FocusRequester()

                    Scaffold(
                        topBar = {
                            var borderThickness = if(focusBoxNumber == 0) 10.dp else 0.dp
                            Box(modifier = Modifier
                                .background(Color(0, 38, 150, 153))
                                .height(250.dp)
                                .fillMaxWidth()
                                .clickable {  }
                                .focusProperties { down = contentFocusRequester }
                                .border(BorderStroke(borderThickness, Color.Red))
                            ){}
                        }
                    ) { paddingValues ->
                        Box(modifier = Modifier
                            .focusRequester(contentFocusRequester)
                            .padding(top = paddingValues.calculateTopPadding())
                        ) {
                            Page2()
                        }
                    }
                }
            }

        }
    }
}

@Composable
fun Page2() {
    Column(
        modifier = Modifier
            .onFocusChanged { if (!it.hasFocus) focusBoxNumber = 0 }
            .verticalScroll(rememberScrollState())
    ) {
        for (number in 1..5) {
            FocusablePageDivider(number = number)
        }
    }
}

@Composable
fun FocusablePageDivider(number: Int) {
    var borderThickness = if(focusBoxNumber == number) 10.dp else 0.dp
    Box (modifier = Modifier
        .padding(bottom = 100.dp)
        .border(BorderStroke(borderThickness, Color.Red))
        .fillMaxWidth()
        .height(250.dp)
        .background(Color.Blue)
        .onFocusChanged { if (it.isFocused) focusBoxNumber = number }
        .clickable { }
    )
}

Upvotes: 1

Views: 896

Answers (1)

BenjyTec
BenjyTec

Reputation: 10887

You are using the modifier

padding(top = paddingValues.calculateTopPadding())`

which makes sure that the top edge of content is placed below the bottom edge of the TopAppBar. The easiest way could be to just remove this, however, you will get a linter warning because you should apply the paddingValues to the content Composable. Using this approach also could have side effects if you use a BottomNavigation.

If you want to avoid the linter warning, you can instead provide the TopAppBar in the Scaffold content parameter instead of the topBar parameter. Use a Box to stack the TopAppBar on top of the actual content.

Scaffold(
    topBar = {}
) { paddingValues ->

    Box(modifier = Modifier.fillMaxSize()) {
        MyContent()
        TopAppBar(
            title = { Text("App") },
            backgroundColor = Color.Transparent.copy(alpha = 0.1f),
        )
    }
}

If needed, you can add a top padding to the MyContent Composable, so that before scrolling, the content will be below the TopAppBar.

Upvotes: 0

Related Questions