-
-
Save TylerMcCraw/b9af98be21e31f09bf8835e2568f9e48 to your computer and use it in GitHub Desktop.
Parallax effect with Jetpack Compose
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val context = LocalContext.current | |
val scope = rememberCoroutineScope() | |
var data by remember { mutableStateOf<SensorData?>(null) } | |
DisposableEffect(Unit) { | |
val dataManager = SensorDataManager(context) | |
dataManager.init() | |
scope.launch { | |
dataManager.data | |
.receiveAsFlow() | |
.onEach { data = it } | |
.collect() | |
} | |
onDispose { | |
dataManager.cancel() | |
} | |
} | |
if (data != null) { | |
Box( | |
modifier = Modifier | |
.fillMaxWidth() | |
.align(Alignment.Center) | |
) { | |
// Blurred image as glow shadow for the card | |
// Will move in opposite direction of Image Card to reveal itself when inclined | |
Image( | |
painter = painterResource(id = R.drawable.beach), | |
modifier = Modifier | |
.offset( | |
x = (-data!!.roll * 0.5).dp, | |
y = (data!!.pitch * 0.7).dp | |
) | |
.width(256.dp) | |
.height(356.dp) | |
.blur(radius = 24.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded), | |
contentDescription = null, | |
contentScale = ContentScale.FillHeight, | |
) | |
// White edge shadow (should move slightly slower than the card) | |
Box( | |
modifier = Modifier | |
.offset( | |
x = (data!!.roll * 0.35).dp, | |
y = (-data!!.pitch * 0.35).dp | |
) | |
.width(300.dp) | |
.height(400.dp) | |
.background( | |
color = Color.White.copy(alpha = 0.3f), | |
shape = RoundedCornerShape(16.dp) | |
), | |
) | |
// Image Card (with slight parallax for the image itself) | |
Image( | |
painter = painterResource(id = R.drawable.beach), | |
modifier = Modifier | |
.offset( | |
x = (data!!.roll * 0.4).dp, | |
y = (-data!!.pitch * 0.4).dp | |
) | |
.width(300.dp) | |
.height(400.dp) | |
.clip(RoundedCornerShape(16.dp)), | |
contentDescription = null, | |
contentScale = ContentScale.FillHeight, | |
alignment = BiasAlignment( | |
horizontalBias = -(data!!.roll * 0.001).toFloat(), | |
verticalBias = 0f, | |
) | |
) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SensorDataManager (context: Context): SensorEventListener { | |
private val sensorManager by lazy { | |
context.getSystemService(Context.SENSOR_SERVICE) as SensorManager | |
} | |
fun init() { | |
Log.d("SensorDataManager", "init") | |
val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) | |
val magnetometer = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) | |
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI) | |
sensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_UI) | |
} | |
private var gravity: FloatArray? = null | |
private var geomagnetic: FloatArray? = null | |
val data: Channel<SensorData> = Channel(Channel.UNLIMITED) | |
override fun onSensorChanged(event: SensorEvent?) { | |
if (event?.sensor?.type == Sensor.TYPE_GRAVITY) | |
gravity = event.values | |
if (event?.sensor?.type == Sensor.TYPE_MAGNETIC_FIELD) | |
geomagnetic = event.values | |
if (gravity != null && geomagnetic != null) { | |
var r = FloatArray(9) | |
var i = FloatArray(9) | |
if (SensorManager.getRotationMatrix(r, i, gravity, geomagnetic)) { | |
var orientation = FloatArray(3) | |
SensorManager.getOrientation(r, orientation) | |
data.trySend( | |
SensorData( | |
roll = orientation[2] * 180 / Math.PI, | |
pitch = orientation[1] * 180 / Math.PI | |
) | |
) | |
} | |
} | |
} | |
fun cancel() { | |
Log.d("SensorDataManager", "cancel") | |
sensorManager.unregisterListener(this) | |
} | |
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {} | |
} | |
data class SensorData( | |
val roll: Double, | |
val pitch: Double | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment