Cómo voltear una vista en Android usando Kotlin


Si se requiere voltear una vista como si fuese un juego de descubrir una carta, se puede hacer con la animación (Flip Card Animation)

Preparativos

primero debemos declarar las animaciones siguientes en el directorio res/animator

archivo flip_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <objectAnimator
        android:duration="0"
        android:propertyName="alpha"
        android:valueFrom="1.0"
        android:valueTo="0.0" />
    
    <objectAnimator
        android:duration="750"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:propertyName="rotationY"
        android:repeatMode="reverse"
        android:valueFrom="-180"
        android:valueTo="0" />

    <objectAnimator
        android:duration="0"
        android:propertyName="alpha"
        android:startOffset="350"
        android:valueFrom="0.0"
        android:valueTo="1.0" />
</set>

archivo flip_out.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <objectAnimator
        android:duration="750"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:propertyName="rotationY"
        android:valueFrom="0"
        android:valueTo="180" />

    <objectAnimator
        android:duration="0"
        android:propertyName="alpha"
        android:startOffset="350"
        android:valueFrom="1.0"
        android:valueTo="0.0" />
</set>

Diseño de la vistas

Diseñar las caras de la carta, la cara de detrás y la delante

layout/card_front.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:cardBackgroundColor="@android:color/holo_green_dark"
    app:cardCornerRadius="12dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center">

        <androidx.appcompat.widget.AppCompatImageView
            android:layout_width="56dp"
            android:layout_height="56dp"
            app:srcCompat="@drawable/ic_baseline_android_24"
            app:tint="@android:color/holo_green_light" />
    </LinearLayout>

</com.google.android.material.card.MaterialCardView>


archivo card_back.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:cardCornerRadius="12dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center">

        <androidx.appcompat.widget.AppCompatImageView
            android:layout_width="56dp"
            android:layout_height="56dp"
            app:srcCompat="@drawable/ic_round_favorite_24"
            app:tint="@android:color/holo_red_dark" />
    </LinearLayout>

</com.google.android.material.card.MaterialCardView>


Unir las dos caras en una vista

Ahora donde queremos mostrar la vista con las dos caras

<FrameLayout
    android:id="@+id/card_flip"
    android:layout_width="150dp"
    android:layout_height="240dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <FrameLayout
        android:id="@+id/card_face_front"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <include
            layout="@layout/card_front"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>


    <FrameLayout
        android:id="@+id/card_face_back"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone">

        <include
            layout="@layout/card_back"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>


</FrameLayout>

Animación Card Flip Animator

Con el método FlipCard podemos animar la vistas, especificando la cara visible y la cara oculta

private fun flipCard(context: Context, visibleView: View, inVisibleView: View) {
    try {
        visibleView.visibility = View.VISIBLE
        val scale = context.resources.displayMetrics.density
        val cameraDist = 8000F * scale
        visibleView.cameraDistance = cameraDist
        inVisibleView.cameraDistance = cameraDist
        val flipOutAnimatorSet = AnimatorInflater.loadAnimator(context, R.animator.flip_out) as AnimatorSet
        flipOutAnimatorSet.setTarget(inVisibleView)
        val flipInAnimatorSet = AnimatorInflater.loadAnimator(context, R.animator.flip_in) as AnimatorSet
        flipInAnimatorSet.setTarget(visibleView)

        flipOutAnimatorSet.start()
        flipInAnimatorSet.start()
        flipInAnimatorSet.doOnEnd {
            inVisibleView.visibility = View.GONE
            binding.cardFlip.isEnabled = true
        }
    } catch (e: Exception) {
        Log.e(TAG, "flipCard: $e")
    }
}

Su uso

Si queremos que en cada toque encima de la carta se volteé, el falg isCardFront es para saber a que cara se encuentra y la it.isEnabled es para prevenir multiples toques mientras se ejecuta la animación

private var isCardFront = true
...
binding.cardFlip.setOnClickListener {
    it.isEnabled = false
    isCardFront = !isCardFront

    if (isCardFront) {
        flipCard(requireContext(), binding.cardFaceFront, binding.cardFaceBack)

    } else {
        flipCard(requireContext(), binding.cardFaceBack, binding.cardFaceFront)

    }
}

Demostración

Dejo video demostrativo para ver su animación Flip Card Animation

Extra en Jetpack Compose

Si se quiere realizar con jetpack compose dejo enlace de la fuente: https://fvilarino.medium.com/creating-a-rotating-card-in-jetpack-compose-ba94c7dd76fb

Anuncio publicitario

Publicado por Codelaby

Mobile DevDesigner

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

A %d blogueros les gusta esto: