能否在android系统的偏好设置中添加动画,就像在导航组件中一样。

问题描述 投票:6回答:1

有没有可能像导航组件里有一个动画一样,给喜好的碎片变化添加一个动画?安卓指南

所以我想执行类似这里的事情。

<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>
...

更新:

我想说明一下:我想使用导航组件和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>

android kotlin android-animation android-preferences android-jetpack
1个回答
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()
    }
}

当然现在你需要将你想要的动画添加到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>

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>

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>

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>

现在剩下的就是使用它了。你有很多选择,比如传递bundle参数,决定用hideshow代替addremove。(注意*如果你隐藏了show,动画可能无法工作,但你不会失去加载的webview或其他下载的视图,所以这真的取决于你的使用情况。

MainActivity.kt

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

    }

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

我添加了日志以增加你阅读的清晰度,还有一个删除片段的功能,以防你只需要它消失。

把它想象成一个扩展,你只需把它放在任何项目中,然后按原样使用即可。你不必深入研究它,这将处理你所要求的。

祝你编码愉快

© www.soinside.com 2019 - 2024. All rights reserved.