可以像在导航组件中一样在 android 中的首选项中添加动画

kau*_*lex 6 android android-preferences android-animation kotlin android-jetpack

是否有可能像导航组件中那样添加动画来片段化偏好的变化?安卓指南

所以我想在这里执行类似的操作:

<fragment>
    <action
        android:id="@+id/action_a_to_b"
        app:destination="@id/b"
        app:enterAnim="@anim/slide_in_right"
        app:exitAnim="@anim/slide_out_right"
        app:popEnterAnim="@anim/slide_in_left"
        app:popExitAnim="@anim/slide_out_left" />

</fragment>
...
Run Code Online (Sandbox Code Playgroud)

更新:

明确地说:我想将导航组件与 Jetpack 首选项结合使用。问题是,jetpack 会自动处理首选项中的动画,但我想要另一个动画,然后是默认的淡入/淡出。所以我只想覆盖它。即:有没有办法像在 hirachy 中那样在 xml 中添加动画?

<PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto">

<PreferenceCategory
    app:key="help_category"
    app:title="Help">

    <Preference
        app:fragment="com.example.SyncFragment"
        app:key="feedback"
        app:summary="Report technical issues or suggest new features"
        app:title="Send feedback"/>

</PreferenceCategory>
Run Code Online (Sandbox Code Playgroud)

Sam*_*Sam 2

我假设因为您询问如何对片段进行动画进出,所以您没有使用导航框架,因为它是免费提供的。因此,让我们假设您没有使用它,并深入研究如何实现这一点。

首先,我们需要有一个方法来处理交换片段。让我们创建一个扩展类。我在所有示例中都使用 Kotlin 和 Androidx

FragmentExt.kt

import android.app.Activity
import android.app.ActivityManager
import android.content.Context
import android.os.Bundle
import androidx.annotation.IdRes
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import <YOUR PROJECT R FILE>

/*
 * Written by Sam Rosewall App Studio 35
*/
val Activity.activityManager: ActivityManager
    get() = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

fun FragmentActivity.swapFragment(
    fragContainerId: Int,
    newFragment: Fragment?,
    oldFragment: Fragment? = null,
    bundle: Bundle? = null,
    hideCurrentFrag: Boolean = false,
    addToBackStack:Boolean = false
) {
    if (newFragment == null || newFragment.isVisible) {
        loge("swapFragment called on already visible fragment")
        return
    }

    logv("swapFragment( ${newFragment.javaClass.simpleName} )")
    val currentFragBundle = newFragment.arguments
    if (currentFragBundle == null && bundle != null) {
        newFragment.arguments = bundle
        logv("current bundle is null, so setting new bundle passed in")
    } else if (bundle != null) {
        newFragment.arguments?.putAll(bundle)
        logv("current fragment bundle was not null, so add new bundle to it")
    }

    //Ensure no pending transactions are paused or incomplete
    val fragmentManager = supportFragmentManager
    fragmentManager.executePendingTransactions()
    val fragmentTransaction = fragmentManager.beginTransaction()

    //Make sure the requested fragment isn't already on the screen before adding it
    if (newFragment.isAdded) {
        logv("Fragment is already added")
        if (newFragment.isHidden) {
            logv("Fragment is hidden, so show it")
            fragmentTransaction.show(newFragment)
            newFragment.onResume() // since we were hiding it, we call onResume to simulate foreground on fragment

            oldFragment?.let {
                if(hideCurrentFrag) {
                    logv("hideCurrentFlag = true, hiding current fragment $it")
                    fragmentTransaction.hide(it)
                    it.onPause() // since we are hiding it, we call onPause to simulate background on fragment
                }else{
                    logv("hideCurrentFlag = false, removing current fragment $it")
                    fragmentTransaction.remove(it)
                }
            }
        }else{
            logv("Fragment is already visible")
        }
    }else if(oldFragment == null){
        if (addToBackStack) {
            fragmentTransaction.setCustomAnimations(R.anim.in_from_right_to_left, R.anim.out_to_left, R.anim.in_from_left_to_right, R.anim.out_to_right )
            fragmentTransaction.addToBackStack(null)
        }
        logv("oldFragment = null, so Replacing active contents of container with Fragment ${newFragment.javaClass.simpleName}")
        fragmentTransaction.replace(fragContainerId, newFragment)
    }else{
        logv("Fragment is not added, and there is existing fragment to remove, so adding to the screen ${newFragment.javaClass.simpleName}")
        fragmentTransaction.add(fragContainerId, newFragment)

        if(hideCurrentFrag) {
            logv("hideCurrentFlag = true, hiding current fragment $oldFragment")
            fragmentTransaction.hide(oldFragment)
            oldFragment.onPause() // since we are hiding it, we call onPause to simulate background on fragment
        }else{
            logv("hideCurrentFlag = false, removing current fragment $oldFragment")
            fragmentTransaction.setCustomAnimations(R.anim.in_from_right_to_left, R.anim.out_to_left, R.anim.in_from_left_to_right, R.anim.out_to_right )
            fragmentTransaction.remove(oldFragment)
        }
    }

    logv("committing swap fragment transaction")
    fragmentTransaction.commit()
}

fun FragmentActivity.removeFragment(@IdRes fragContainerId: Int) {
    val fragmentManager = supportFragmentManager
    fragmentManager.findFragmentById(fragContainerId)?.let {
        fragmentManager.executePendingTransactions()
        val transaction = fragmentManager.beginTransaction()
        transaction.remove(it)
        transaction.commit()
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,现在您需要将所需的动画添加到 anims 目录中。

res->anim->[在此处添加文件]

in_from_left_to_right.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">
    <translate
        android:duration="500"
        android:fromXDelta="-100%"
        android:fromYDelta="0%"
        android:toXDelta="0%"
        android:toYDelta="0%" />
</set>
Run Code Online (Sandbox Code Playgroud)

in_from_right_to_left.xml

    <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">
    <translate
        android:duration="500"
        android:fromXDelta="100%"
        android:fromYDelta="0%"
        android:toXDelta="0%"
        android:toYDelta="0%" />
    </set>
Run Code Online (Sandbox Code Playgroud)

out_to_right.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">
    <translate
        android:duration="500"
        android:fromXDelta="0%"
        android:fromYDelta="0%"
        android:toXDelta="100%"
        android:toYDelta="0%" />
</set>
Run Code Online (Sandbox Code Playgroud)

out_to_left.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">
    <translate
        android:duration="500"
        android:fromXDelta="0%"
        android:fromYDelta="0%"
        android:toXDelta="-100%"
        android:toYDelta="0%" />
</set>
Run Code Online (Sandbox Code Playgroud)

现在剩下的就是使用它。您有很多选择,例如传递捆绑参数、决定隐藏/显示而不是添加/删除。(注意*如果您隐藏/显示动画可能不起作用,但您不会丢失加载的网络视图或其他下载的视图,所以这实际上取决于您的用例。

MainActivity.kt

   private fun changeToMyFragment() {
        if (myFragment == null) {
            myFragment = MyFragment()
        }
        swapFragment(R.id.placeholder_framelayout, myFragment)

    }
Run Code Online (Sandbox Code Playgroud)

就是这样,任何时候你想改变片段,只需使用这个方法“swapFragment”并传递你想要的片段。如果你需要的话,其他参数都是可选的,可以进行额外的控制。

我添加了日志以方便您阅读,并添加了删除片段,以防您需要它消失。

可以将其视为一个扩展,您只需将其放入任何项目中并按原样使用即可。您不必深入研究它,这将满足您的要求。

快乐编码!