Skip to content

Commit f416386

Browse files
author
Vasyl Melnyk
committed
Upgraded marqueeHorizontalFadingEdges and updated versions.
1 parent e68de57 commit f416386

6 files changed

Lines changed: 197 additions & 41 deletions

File tree

ComposeFadingEdges/src/main/kotlin/com/gigamole/composefadingedges/FadingEdges.kt

Lines changed: 83 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
2121
import androidx.compose.foundation.verticalScroll
2222
import androidx.compose.runtime.getValue
2323
import androidx.compose.runtime.mutableFloatStateOf
24+
import androidx.compose.runtime.mutableStateOf
2425
import androidx.compose.runtime.remember
2526
import androidx.compose.runtime.setValue
2627
import androidx.compose.ui.Modifier
@@ -37,7 +38,9 @@ import androidx.compose.ui.graphics.drawscope.DrawScope
3738
import androidx.compose.ui.graphics.graphicsLayer
3839
import androidx.compose.ui.layout.layout
3940
import androidx.compose.ui.platform.LocalDensity
41+
import androidx.compose.ui.unit.Constraints
4042
import androidx.compose.ui.unit.Dp
43+
import androidx.compose.ui.unit.constrainWidth
4144
import androidx.compose.ui.unit.dp
4245
import com.gigamole.composefadingedges.content.FadingEdgesContentType
4346
import com.gigamole.composefadingedges.content.scrollconfig.FadingEdgesScrollConfig
@@ -56,13 +59,17 @@ import kotlin.math.min
5659
* When [isMarqueeAutoLayout] is enabled, the origin width is extended based on the provided [length] and [gravity], while maintaining the same offset. This ensures that
5760
* when fading edges [length] paddings are applied to the marquee text, the text remains positioned at its origin location. It is important to leave sufficient free space
5861
* around the marquee to ensure the effect is drawn correctly. On the other hand, when [isMarqueeAutoLayout] is disabled, the fading edges length paddings are applied to
59-
* the marquee text, and the origin position is offset by the [length]. In this case, you need to manually handle this padding offset.
62+
* the marquee text, and the origin position is offset by the [length]. In this case, you need to manually handle this padding offset. In the [isMarqueeAutoLayout] the
63+
* [isMarqueeAutoPadding] is automatically true.
64+
*
65+
* When the text content is unfit, the marquee and [horizontalFadingEdges] will not be applied.
6066
*
6167
* @param gravity The [FadingEdgesGravity].
6268
* @param length The fading edges length.
6369
* @param fillType The [FadingEdgesFillType].
6470
* @param isMarqueeAutoLayout Determines whether the [horizontalFadingEdges] and text marquee should be automatically aligned during the layout process to accommodate
6571
* additional text paddings required for proper fading edges drawing.
72+
* @param isMarqueeAutoPadding Determines if padding values according to the [gravity] and [length] should be applied.
6673
* @param marqueeProvider The custom or default [basicMarquee] provider.
6774
* @return The [Modifier] with extended width in case of [isMarqueeAutoLayout] is enabled, [horizontalFadingEdges], provided marquee with [marqueeProvider], and
6875
* additional horizontal paddings.
@@ -73,21 +80,39 @@ fun Modifier.marqueeHorizontalFadingEdges(
7380
length: Dp = FadingEdgesDefaults.Length,
7481
fillType: FadingEdgesFillType = FadingEdgesDefaults.FillType,
7582
isMarqueeAutoLayout: Boolean = FadingEdgesDefaults.IsMarqueeAutoLayout,
76-
marqueeProvider: Modifier.() -> Modifier
77-
): Modifier =
78-
then(
79-
if (isMarqueeAutoLayout) {
80-
Modifier.layout { measurable, constraints ->
81-
val lengthPx = length.roundToPx()
82-
val widthLength = when (gravity) {
83-
FadingEdgesGravity.All -> {
84-
lengthPx * 2
85-
}
86-
FadingEdgesGravity.Start,
87-
FadingEdgesGravity.End -> {
88-
lengthPx
89-
}
83+
isMarqueeAutoPadding: Boolean = FadingEdgesDefaults.IsMarqueeAutoPadding,
84+
marqueeProvider: () -> Modifier
85+
): Modifier = composed {
86+
var isMarqueeAndFadingEdgesVisible by remember { mutableStateOf(false) }
87+
var isMarqueeAutoLayoutApplied by remember { mutableStateOf(false) }
88+
89+
Modifier
90+
.layout { measurable, constraints ->
91+
val lengthPx = length.roundToPx()
92+
val widthLength = when (gravity) {
93+
FadingEdgesGravity.All -> {
94+
lengthPx * 2
9095
}
96+
FadingEdgesGravity.Start,
97+
FadingEdgesGravity.End -> {
98+
lengthPx
99+
}
100+
}
101+
102+
val contentConstraints = constraints.copy(maxWidth = Constraints.Infinity)
103+
val contentPlaceable = measurable.measure(contentConstraints)
104+
val containerWidth = constraints.constrainWidth(contentPlaceable.width)
105+
val contentWidth = contentPlaceable.width -
106+
if (isMarqueeAutoLayout && isMarqueeAutoLayoutApplied) {
107+
widthLength
108+
} else {
109+
0
110+
}
111+
112+
isMarqueeAndFadingEdgesVisible = contentWidth > containerWidth
113+
114+
if (isMarqueeAutoLayout && isMarqueeAndFadingEdgesVisible) {
115+
isMarqueeAutoLayoutApplied = true
91116

92117
// Extend the content width for fading edges and an additional text padding later.
93118
val placeable = measurable.measure(
@@ -96,6 +121,20 @@ fun Modifier.marqueeHorizontalFadingEdges(
96121
)
97122
)
98123

124+
layout(
125+
width = placeable.width,
126+
height = placeable.height
127+
) {
128+
placeable.placeWithLayer(
129+
x = 0,
130+
y = 0
131+
)
132+
}
133+
} else {
134+
isMarqueeAutoLayoutApplied = false
135+
136+
val placeable = measurable.measure(constraints)
137+
99138
layout(
100139
width = placeable.width,
101140
height = placeable.height
@@ -106,30 +145,39 @@ fun Modifier.marqueeHorizontalFadingEdges(
106145
)
107146
}
108147
}
109-
} else {
110-
Modifier
111148
}
112-
)
113-
.horizontalFadingEdges(
114-
gravity = gravity,
115-
length = length,
116-
fillType = fillType
117-
)
118-
.then(marqueeProvider())
119149
.then(
120-
// Applying an additional padding to text, so fading edges dont cover it, at its origin position.
121-
when (gravity) {
122-
FadingEdgesGravity.All -> {
123-
Modifier.padding(horizontal = length)
124-
}
125-
FadingEdgesGravity.Start -> {
126-
Modifier.padding(start = length)
127-
}
128-
FadingEdgesGravity.End -> {
129-
Modifier.padding(end = length)
130-
}
150+
if (isMarqueeAndFadingEdgesVisible) {
151+
Modifier
152+
.horizontalFadingEdges(
153+
gravity = gravity,
154+
length = length,
155+
fillType = fillType
156+
)
157+
.then(marqueeProvider())
158+
.then(
159+
if (isMarqueeAutoLayout || isMarqueeAutoPadding) {
160+
// Applying an additional padding to text, so fading edges dont cover it, at its origin position.
161+
when (gravity) {
162+
FadingEdgesGravity.All -> {
163+
Modifier.padding(horizontal = length)
164+
}
165+
FadingEdgesGravity.Start -> {
166+
Modifier.padding(start = length)
167+
}
168+
FadingEdgesGravity.End -> {
169+
Modifier.padding(end = length)
170+
}
171+
}
172+
} else {
173+
Modifier
174+
}
175+
)
176+
} else {
177+
Modifier
131178
}
132179
)
180+
}
133181

134182
/**
135183
* The [Modifier] to add horizontal [fadingEdges] with a [FadingEdgesContentType.Static] content type. The fading edges are always fully shown.

ComposeFadingEdges/src/main/kotlin/com/gigamole/composefadingedges/FadingEdgesDefaults.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,12 @@ object FadingEdgesDefaults {
2929
* @see marqueeHorizontalFadingEdges
3030
*/
3131
const val IsMarqueeAutoLayout: Boolean = true
32+
33+
/**
34+
* Determines whether the [horizontalFadingEdges] and horizontal text marquee should apply paddings paddings according to the gravity and length.
35+
*
36+
* @see marqueeHorizontalFadingEdges
37+
*/
38+
const val IsMarqueeAutoPadding: Boolean = true
39+
3240
}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ This `Modifier` comes with common [fading edges params](#fading-edges-modifiers)
121121
|Param|Description|
122122
|-|-|
123123
|`isMarqueeAutoLayout`|Determines whether the `horizontalFadingEdges(...)` and text marquee should be automatically aligned during the layout process to accommodate additional text paddings required for proper fading edges drawing.|
124+
|`isMarqueeAutoPadding`|Determines if padding values according to the `gravity` and `length` should be applied.|
124125
|`marqueeProvider`|The custom or default `basicMarquee` provider.|
125126

126127
## License

app/src/main/kotlin/com/gigamole/composefadingedges/sample/MainActivity.kt

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ import kotlinx.coroutines.delay
8989
import kotlinx.coroutines.launch
9090
import kotlin.random.Random
9191

92+
private val ALPHANUMERIC = ('A'..'Z') + ('a'..'z') + ('0'..'9')
93+
9294
class MainActivity : ComponentActivity() {
9395

9496
override fun onCreate(savedInstanceState: Bundle?) {
@@ -212,7 +214,8 @@ fun MainScreenDemoContent() {
212214
modifier = Modifier
213215
.width(width = 250.dp)
214216
.marqueeHorizontalFadingEdges(isMarqueeAutoLayout = false) {
215-
background(color = Color(0xFFFEECF4))
217+
Modifier
218+
.background(color = Color(0xFFFEECF4))
216219
.basicMarquee(
217220
delayMillis = initialDelay.toInt(),
218221
spacing = MarqueeSpacing.fractionOfContainer(fraction = 0.05F),
@@ -275,6 +278,9 @@ fun MainScreenContent() {
275278
var fadingEdgesFillStopThird by remember { mutableFloatStateOf(FadingEdgesFillTypeDefaults.FillStops.third) }
276279
var fadingEdgesFillSecondStopAlpha by remember { mutableFloatStateOf(FadingEdgesFillTypeDefaults.SecondStopAlpha) }
277280
var fadingEdgesColor by remember { mutableStateOf(FadingEdgesFillTypeDefaults.FadeColor.FadeColor) }
281+
var fadingEdgesMarqueeTextLength by remember { mutableIntStateOf(50) }
282+
var fadingEdgesIsMarqueeAutoLayout by remember { mutableStateOf(FadingEdgesDefaults.IsMarqueeAutoLayout) }
283+
var fadingEdgesIsMarqueeAutoPadding by remember { mutableStateOf(FadingEdgesDefaults.IsMarqueeAutoPadding) }
278284

279285
val fadingEdgesGridSpanCount by remember(fadingEdgesSampleGridSpanCount) {
280286
derivedStateOf {
@@ -296,6 +302,17 @@ fun MainScreenContent() {
296302
}
297303
}
298304
}
305+
val fadingEdgesMarqueeText by remember(
306+
fadingEdgesMarqueeTextLength
307+
) {
308+
derivedStateOf {
309+
buildString {
310+
repeat(fadingEdgesMarqueeTextLength) {
311+
append(ALPHANUMERIC.random())
312+
}
313+
}
314+
}
315+
}
299316
val fadingEdgesScrollConfig by remember(
300317
fadingEdgesSampleScrollConfig,
301318
fadingEdgesScrollAnimationSpec,
@@ -444,6 +461,9 @@ fun MainScreenContent() {
444461
fadingEdgesFillStopThird = FadingEdgesFillTypeDefaults.FillStops.third
445462
fadingEdgesFillSecondStopAlpha = FadingEdgesFillTypeDefaults.SecondStopAlpha
446463
fadingEdgesColor = FadingEdgesFillTypeDefaults.FadeColor.FadeColor
464+
fadingEdgesMarqueeTextLength = 50
465+
fadingEdgesIsMarqueeAutoLayout = FadingEdgesDefaults.IsMarqueeAutoLayout
466+
fadingEdgesIsMarqueeAutoPadding = FadingEdgesDefaults.IsMarqueeAutoPadding
447467

448468
coroutineScope.launch {
449469
resetScrolls()
@@ -1048,7 +1068,7 @@ fun MainScreenContent() {
10481068
modifier = Modifier
10491069
.weight(weight = 1.0F)
10501070
.marqueeHorizontalFadingEdges(length = 8.dp) {
1051-
basicMarquee()
1071+
Modifier.basicMarquee()
10521072
},
10531073
text = "IS LERP BY DIFFERENCE FOR PARTIAL CONTENT:",
10541074
style = MaterialTheme.typography.labelLarge,
@@ -1205,6 +1225,85 @@ fun MainScreenContent() {
12051225
Spacer(modifier = Modifier.height(height = 4.dp))
12061226
}
12071227

1228+
if (fadingEdgesContentType == FadingEdgesContentType.Static) {
1229+
Text(
1230+
text = "MARQUEE TEXT LENGTH:",
1231+
style = MaterialTheme.typography.labelLarge
1232+
)
1233+
Slider(
1234+
modifier = Modifier.fillMaxWidth(),
1235+
value = fadingEdgesMarqueeTextLength.toFloat(),
1236+
onValueChange = {
1237+
fadingEdgesMarqueeTextLength = it.toInt()
1238+
},
1239+
valueRange = 0.0F..100.0F,
1240+
steps = 11
1241+
)
1242+
Row(
1243+
modifier = Modifier.fillMaxWidth(),
1244+
horizontalArrangement = Arrangement.spacedBy(space = 20.dp),
1245+
verticalAlignment = Alignment.CenterVertically
1246+
) {
1247+
Text(
1248+
modifier = Modifier.weight(weight = 1.0F),
1249+
text = "IS MARQUEE AUTO LAYOUT:",
1250+
style = MaterialTheme.typography.labelLarge,
1251+
maxLines = 1
1252+
)
1253+
Switch(
1254+
modifier = Modifier.padding(start = 8.dp),
1255+
checked = fadingEdgesIsMarqueeAutoLayout,
1256+
onCheckedChange = {
1257+
fadingEdgesIsMarqueeAutoLayout = it
1258+
}
1259+
)
1260+
}
1261+
Row(
1262+
modifier = Modifier.fillMaxWidth(),
1263+
horizontalArrangement = Arrangement.spacedBy(space = 20.dp),
1264+
verticalAlignment = Alignment.CenterVertically
1265+
) {
1266+
Text(
1267+
modifier = Modifier.weight(weight = 1.0F),
1268+
text = "IS MARQUEE AUTO PADDING:",
1269+
style = MaterialTheme.typography.labelLarge,
1270+
maxLines = 1
1271+
)
1272+
Switch(
1273+
modifier = Modifier.padding(start = 8.dp),
1274+
checked = fadingEdgesIsMarqueeAutoPadding,
1275+
onCheckedChange = {
1276+
fadingEdgesIsMarqueeAutoPadding = it
1277+
}
1278+
)
1279+
}
1280+
Box(
1281+
modifier = Modifier
1282+
.fillMaxWidth()
1283+
.padding(vertical = 20.dp)
1284+
.border(
1285+
color = Color.Red.copy(alpha = 0.25F),
1286+
width = 1.dp
1287+
)
1288+
) {
1289+
Text(
1290+
modifier = Modifier
1291+
.fillMaxWidth()
1292+
.marqueeHorizontalFadingEdges(
1293+
gravity = FadingEdgesGravity.All,
1294+
length = fadingEdgesLength,
1295+
fillType = fadingEdgesFillType,
1296+
isMarqueeAutoLayout = fadingEdgesIsMarqueeAutoLayout,
1297+
isMarqueeAutoPadding = fadingEdgesIsMarqueeAutoPadding
1298+
) {
1299+
Modifier.basicMarquee(iterations = Int.MAX_VALUE)
1300+
},
1301+
text = fadingEdgesMarqueeText,
1302+
style = MaterialTheme.typography.labelLarge,
1303+
maxLines = 1
1304+
)
1305+
}
1306+
}
12081307

12091308
Button(
12101309
modifier = Modifier.fillMaxWidth(),

gradle/libs.versions.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[versions]
22

33
# Android/Kotlin
4-
android_gradle_plugin_version = "8.1.1"
4+
android_gradle_plugin_version = "8.1.2"
55
androidx_ktx_version = "1.12.0"
66
kotlin_version = "1.9.10"
77

@@ -10,8 +10,8 @@ ksp_version = "1.9.10-1.0.13"
1010

1111
# Compose
1212
compose_compiler_version = "1.5.3"
13-
compose_bom_version = "2023.09.01"
14-
compose_activity_version = "1.7.2"
13+
compose_bom_version = "2023.10.01"
14+
compose_activity_version = "1.8.0"
1515
compose_color_picker_version = "0.7.0"
1616

1717
[plugins]

plugins/src/main/java/ProjectConfig.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import org.gradle.jvm.toolchain.JavaLanguageVersion
55

66
object ProjectConfig {
77
const val versionCode = 1
8-
const val versionName = "1.0.3"
8+
const val versionName = "1.0.4"
99

1010
const val namespace = "com.gigamole.composefadingedges"
1111
const val group = "com.github.GIGAMOLE"

0 commit comments

Comments
 (0)