Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1a657aa

Browse files
add frosted glass sample with RenderEffect
1 parent 41267a8 commit 1a657aa

File tree

1 file changed

+170
-30
lines changed

1 file changed

+170
-30
lines changed

‎Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/chapter6_graphics/Tutorial40_2RenderEffect1.kt

Lines changed: 170 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import androidx.compose.foundation.Canvas
1111
import androidx.compose.foundation.Image
1212
import androidx.compose.foundation.background
1313
import androidx.compose.foundation.border
14+
import androidx.compose.foundation.clickable
1415
import androidx.compose.foundation.layout.Arrangement
1516
import androidx.compose.foundation.layout.Box
1617
import androidx.compose.foundation.layout.Column
18+
import androidx.compose.foundation.layout.PaddingValues
1719
import androidx.compose.foundation.layout.Spacer
1820
import androidx.compose.foundation.layout.aspectRatio
1921
import androidx.compose.foundation.layout.fillMaxSize
@@ -22,21 +24,22 @@ import androidx.compose.foundation.layout.height
2224
import androidx.compose.foundation.layout.padding
2325
import androidx.compose.foundation.layout.width
2426
import androidx.compose.foundation.lazy.LazyColumn
27+
import androidx.compose.foundation.lazy.LazyRow
28+
import androidx.compose.foundation.lazy.rememberLazyListState
2529
import androidx.compose.foundation.rememberScrollState
2630
import androidx.compose.foundation.shape.RoundedCornerShape
2731
import androidx.compose.foundation.verticalScroll
2832
import androidx.compose.material3.Slider
2933
import androidx.compose.material3.Text
3034
import androidx.compose.runtime.Composable
31-
import androidx.compose.runtime.LaunchedEffect
3235
import androidx.compose.runtime.getValue
3336
import androidx.compose.runtime.mutableFloatStateOf
34-
import androidx.compose.runtime.mutableIntStateOf
3537
import androidx.compose.runtime.remember
3638
import androidx.compose.runtime.setValue
3739
import androidx.compose.ui.Alignment
3840
import androidx.compose.ui.Modifier
3941
import androidx.compose.ui.draw.clipToBounds
42+
import androidx.compose.ui.draw.drawWithCache
4043
import androidx.compose.ui.draw.drawWithContent
4144
import androidx.compose.ui.geometry.Offset
4245
import androidx.compose.ui.graphics.Brush
@@ -59,15 +62,16 @@ import androidx.compose.ui.platform.LocalDensity
5962
import androidx.compose.ui.res.imageResource
6063
import androidx.compose.ui.res.painterResource
6164
import androidx.compose.ui.tooling.preview.Preview
65+
import androidx.compose.ui.unit.Dp
6266
import androidx.compose.ui.unit.IntSize
6367
import androidx.compose.ui.unit.dp
68+
import androidx.compose.ui.unit.roundToIntSize
6469
import androidx.compose.ui.unit.sp
6570
import com.smarttoolfactory.tutorial1_1basics.R
6671
import com.smarttoolfactory.tutorial1_1basics.ui.backgroundColor
6772
import com.smarttoolfactory.tutorial1_1basics.ui.components.StyleableTutorialText
6873
import com.smarttoolfactory.tutorial1_1basics.ui.components.TutorialHeader
6974
import com.smarttoolfactory.tutorial1_1basics.ui.components.TutorialText2
70-
import kotlinx.coroutines.delay
7175
import org.intellij.lang.annotations.Language
7276
import kotlin.math.roundToInt
7377

@@ -77,7 +81,6 @@ fun Tutorial6_40Screen2() {
7781
TutorialContent()
7882
}
7983

80-
8184
@Composable
8285
private fun TutorialContent() {
8386
Column(modifier = Modifier.padding(8.dp)) {
@@ -507,19 +510,11 @@ fun RenderNodeSample() {
507510

508511
val graphicsLayer = rememberGraphicsLayer()
509512

510-
var counter by remember {
511-
mutableIntStateOf(0)
512-
}
513-
514-
LaunchedEffect(Unit) {
515-
while (true) {
516-
delay(60)
517-
counter++
518-
}
519-
}
513+
val state = rememberLazyListState()
520514

521515
Box {
522516
LazyColumn(
517+
state = state,
523518
modifier = Modifier
524519
.background(backgroundColor)
525520
.fillMaxSize()
@@ -536,20 +531,6 @@ fun RenderNodeSample() {
536531
) {
537532
this@drawWithContent.drawContent()
538533
}
539-
540-
// val recordingCanvas = contentNode.beginRecording()
541-
// canvasHolder.drawInto(recordingCanvas) {
542-
// drawContext.also {
543-
// it.layoutDirection = layoutDirection
544-
// it.size = size
545-
// it.canvas = this
546-
// }
547-
//// this@drawWithContent.drawContent()
548-
// drawLayer(graphicsLayer)
549-
// }
550-
//
551-
// contentNode.endRecording()
552-
553534
},
554535
verticalArrangement = Arrangement.spacedBy(8.dp)
555536
) {
@@ -600,8 +581,6 @@ fun RenderNodeSample() {
600581
)
601582
)
602583

603-
println("Drawing...$counter")
604-
605584
drawIntoCanvas { canvas: Canvas ->
606585
val recordingCanvas = contentNode.beginRecording()
607586
canvasHolder.drawInto(recordingCanvas) {
@@ -626,4 +605,165 @@ fun RenderNodeSample() {
626605
)
627606
}
628607
}
608+
}
609+
610+
fun Modifier.frostedGlass(height: Dp) = this.then(
611+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
612+
Modifier.drawWithCache {
613+
val topBarHeightPx = height.toPx()
614+
615+
val blurLayer = obtainGraphicsLayer().apply {
616+
renderEffect = RenderEffect
617+
.createBlurEffect(16f, 16f, Shader.TileMode.DECAL)
618+
.asComposeRenderEffect()
619+
}
620+
621+
onDrawWithContent {
622+
blurLayer.record(size.copy(height = topBarHeightPx).roundToIntSize()) {
623+
this@onDrawWithContent.drawContent()
624+
}
625+
626+
drawLayer(blurLayer)
627+
clipRect(top = topBarHeightPx) {
628+
this@onDrawWithContent.drawContent()
629+
}
630+
}
631+
}
632+
} else {
633+
Modifier
634+
}
635+
)
636+
637+
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
638+
@Preview(showBackground = true)
639+
@Composable
640+
fun PartialBlurTest() {
641+
642+
val scrollState = rememberLazyListState()
643+
val topBarHeight = 180.dp
644+
645+
LazyColumn(
646+
state = scrollState,
647+
modifier = Modifier
648+
.fillMaxSize()
649+
.frostedGlass(height = topBarHeight),
650+
verticalArrangement = Arrangement.spacedBy(8.dp)
651+
) {
652+
653+
item {
654+
Spacer(modifier = Modifier.height(topBarHeight))
655+
}
656+
657+
item {
658+
LazyRow(
659+
modifier = Modifier.fillMaxWidth().aspectRatio(2f),
660+
contentPadding = PaddingValues(horizontal = 16.dp),
661+
horizontalArrangement = Arrangement.spacedBy(8.dp)
662+
) {
663+
items(5) {
664+
Image(
665+
modifier = Modifier
666+
.fillParentMaxWidth()
667+
.aspectRatio(2f),
668+
contentScale = ContentScale.Crop,
669+
painter = painterResource(R.drawable.landscape11), contentDescription = null
670+
)
671+
}
672+
}
673+
}
674+
items(100) {
675+
if (it == 5) {
676+
Image(
677+
modifier = Modifier
678+
.fillMaxWidth()
679+
.aspectRatio(.5f),
680+
painter = painterResource(R.drawable.landscape11),
681+
contentScale = ContentScale.Crop,
682+
contentDescription = null
683+
)
684+
} else {
685+
Box(
686+
modifier = Modifier
687+
.clickable {
688+
689+
}
690+
.fillMaxWidth()
691+
.background(Color.White, RoundedCornerShape(16.dp))
692+
.padding(16.dp)
693+
) {
694+
Text("Row $it", fontSize = 22.sp)
695+
}
696+
}
697+
}
698+
}
699+
}
700+
701+
702+
@Language("GLSL")
703+
val CheapFrostedGlassTopBarAGSL =
704+
"""
705+
const vec4 white = vec4(1.0);
706+
707+
uniform shader inputShader;
708+
uniform float barHeight;
709+
710+
vec4 main(vec2 coord) {
711+
if (coord.y > barHeight) {
712+
return inputShader.eval(coord);
713+
} else {
714+
vec2 factor = vec2(3.0);
715+
716+
vec4 color = vec4(0.0);
717+
color += inputShader.eval(coord - 3.0 * factor) * 0.0540540541;
718+
color += inputShader.eval(coord - 2.0 * factor) * 0.1216216216;
719+
color += inputShader.eval(coord - factor) * 0.1945945946;
720+
color += inputShader.eval(coord) * 0.2270270270;
721+
color += inputShader.eval(coord + factor) * 0.1945945946;
722+
color += inputShader.eval(coord + 2.0 * factor) * 0.1216216216;
723+
color += inputShader.eval(coord + 3.0 * factor) * 0.0540540541;
724+
725+
return mix(color, white, 0.7);
726+
}
727+
}
728+
""".trimIndent()
729+
730+
val TopAppBarHeight = 180.dp
731+
732+
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
733+
@Preview(showBackground = true)
734+
@Composable
735+
fun FrostedGlassTopBarTest() {
736+
LazyColumn(
737+
modifier = Modifier
738+
.fillMaxSize()
739+
.graphicsLayer {
740+
val shader = RuntimeShader(CheapFrostedGlassTopBarAGSL)
741+
shader.setFloatUniform("barHeight", TopAppBarHeight.toPx())
742+
val androidRenderEffect = android.graphics.RenderEffect
743+
.createRuntimeShaderEffect(shader, "inputShader")
744+
renderEffect = androidRenderEffect.asComposeRenderEffect()
745+
}
746+
) {
747+
items(100) {
748+
if (it == 5) {
749+
Image(
750+
modifier = Modifier
751+
.fillMaxWidth()
752+
.aspectRatio(2f),
753+
painter = painterResource(R.drawable.landscape11),
754+
contentScale = ContentScale.Crop,
755+
contentDescription = null
756+
)
757+
} else {
758+
Box(
759+
modifier = Modifier
760+
.fillMaxWidth()
761+
.background(Color.White, RoundedCornerShape(16.dp))
762+
.padding(16.dp)
763+
) {
764+
Text("Row $it", fontSize = 22.sp)
765+
}
766+
}
767+
}
768+
}
629769
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /