如何从活动中更改片段的视图/按钮的可见性?

时间:2018-11-01 13:29:55

标签: android android-fragments kotlin

正如标题所示,我正在尝试从活动中更改片段的视图/按钮的可见性。

片段的代码:

package nus.is3261.kotlinapp


import android.content.Context
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 *
 */
class SettingFragment : Fragment() {
    private var listener:SettingFragment.OnFragmentInteractionListener? = null

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_setting, container, false)
        val signIn = view.findViewById<View>(R.id.btn_sign_in)
        signIn.setOnClickListener {
            onButtonPressed("signIn")
        }
        val signOut = view.findViewById<Button>(R.id.btn_sign_out)
        signOut.setOnClickListener {
            onButtonPressed("signOut")
        }
        return view
    }

    fun changeVisibility(isSignedIn : Boolean){
        if (isSignedIn) {
            val signIn = view?.findViewById<View>(R.id.btn_sign_in)
            signIn?.visibility = View.GONE
            val signOut = view?.findViewById<View>(R.id.btn_sign_out)
            signOut?.visibility = View.VISIBLE
        } else {
            val signIn = view?.findViewById<View>(R.id.btn_sign_in)
            signIn?.visibility = View.VISIBLE
            val signOut = view?.findViewById<View>(R.id.btn_sign_out)
            signOut?.visibility = View.GONE

        }
    }

    fun onButtonPressed(str: String) {
        listener?.onFragmentInteraction(str)
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        if (context is SettingFragment.OnFragmentInteractionListener) {
            listener = context
        } else {
            throw RuntimeException(context.toString() + " must implement OnFragmentInteractionListener")
        }
    }

    override fun onDetach() {
        super.onDetach()
        listener = null
    }

    interface OnFragmentInteractionListener {
        fun onFragmentInteraction(str: String)
    }

}

您已经看到,我具有changeVisibility功能,可以更改已设置按钮的可见性。现在,如何从主活动中调用这些功能? 我从主要活动中尝试过此方法,但它很难过:

    private fun updateUI(user: FirebaseUser?) {
        if (user != null) {
//            tvStatus.text = "Google User email: " + user.email!!
//            tvDetail.text = "Firebase User ID: " + user.uid
            val fragment = SettingFragment()
            fragment.changeVisibility(true)
//            btn_sign_in.visibility = View.GONE
//            layout_sign_out_and_disconnect.visibility = View.VISIBLE
        } else {
//            tvStatus.text = "Signed Out"
//            tvDetail.text = null
            val fragment = SettingFragment()
            fragment.changeVisibility(false)
//            btn_sign_in.visibility = View.VISIBLE
//            layout_sign_out_and_disconnect.visibility = View.GONE
        }
    }

这是我的xml文件:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/dracula"
    tools:context=".SettingFragment">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.google.android.gms.common.SignInButton
            android:id="@+id/btn_sign_in"
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:layout_height="0dp"
            android:visibility="visible"
            tools:visibility="gone" />

        <Button
            android:id="@+id/btn_sign_out"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:visibility="gone"
            tools:visibility="visible"
            android:backgroundTint="@color/draculalight"
            android:textColor="@color/green"
            android:text="@string/signout" />

    </LinearLayout>

</FrameLayout>

2 个答案:

答案 0 :(得分:1)

好的,所以您有几个问题,但是如果我只为您提供详尽的一步,那可能是最好的。因此,让我们从头开始。

那么首先是问题

您引用了错误的内存。首先,您将一个片段放入xml中,然后重新创建它的另一个实例,所以这就像倒一杯咖啡,然后从一个新的空杯子中喝出来,然后想知道为什么咖啡不在其中。

现在是解决方案。

首先,您的MainActivity(或片段的父活动)必须包含您要包含的片段的元素。您有两种选择可以执行此操作。让我们从最简单的方法开始,假设它是一个不会被交换掉的静态片段。

选项1(固定片段)

<ParentActivityLayoutOfYourChoice>

    <fragment
        android:name="com.yourpath.FooFragment"
        android:id="@+id/fooFragment"
        android:layout_width="match_parent" 
        android:layout_height="match_parent" />

</ParentActivityLayoutOfYourChoice>

然后在“活动”中,您只需创建一个成员变量并按如下方式访问它:

//lateinit only if you guarantee it will be there in the oncreate
private lateinit var fooFragment: FooFragment
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    fooFragment = findViewById(R.id.fooFragment)
}

fun btnSignIn_onClick(){
    //onSuccess
    fooFragment.isSignedIn(true)
}

选项2(动态片段)

<ParentActivityLayoutOfYourChoice>

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

</ParentActivityLayoutOfYourChoice>

然后,您当然可以在onCreate或适当的位置(例如抽屉式开关片段)中创建Fragment,并将其交换到占位符中。

示例:

//内部MainActivity(或父活动)

 //lazy will new it up the first time you use it.
 private val mFooFragment by lazy {
    FooFragment()
 }

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    swapFragment(mFooFragment) //will auto new the fragment with lazy
}

//Let's start simple before I show you thorough
fun swapFragment(fragment: Fragment){
     val fragmentManager = supportFragmentManager
     val fragmentTransaction = fragmentManager.beginTransaction()
     fragmentTransaction.replace(R.id.fragPlaceholder, fragment)
     fragmentTransaction.commit() //puts the fragment into the placeholder
}

fun btnSignIn_onClick(){
    //onSuccess
    mFooFragment.isSignedIn(true)
}

*现在,在继续之前,我觉得重要的是,我要告诉您,如果您动态交换片段,那么还有更多的余地。您应该处理捆绑软件,应该知道自己是否在隐藏,显示,替换等。处理事务有很多方法。更改片段时,必须确定要隐藏还是要删除。当您将它们放回原处时,它将影响onResume和onCreate的生命周期,因此请明智地进行管理。

我建立了一个简单的swapFragment方法,该方法在BaseActivity的几乎所有项目中使用。我现在将分享这一点,以便更加透彻。

在基本活动中动态存储所选片段并控制片段交换的示例

    private var mSelectedFragment: BaseFragment? = null

    protected fun swapFragment(fragment: BaseFragment, @Nullable bundle: Bundle?, hideCurrentFrag: Boolean = false) {
    if (fragment.isVisible) {
        A35Log.e(mClassTag, "swapFragment called on already visible fragment")
        return
    }

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

    //make sure no pending transactions are still floating and not complete
    val fragmentManager = supportFragmentManager
    fragmentManager.executePendingTransactions()
    val fragmentTransaction = fragmentManager.beginTransaction()

    //Make sure the requested fragment isn't already on the screen before adding it
    if (fragment.isAdded) {
        A35Log.v(mClassTag, "Fragment is already added")
        if (fragment.isHidden) {
            A35Log.v(mClassTag, "Fragment is hidden, so show it")
            fragmentTransaction.show(fragment)
            if(hideCurrentFrag) {
                A35Log.v(mClassTag, "hideCurrentFlag = true, hiding current fragment $mSelectedFragment")
                fragmentTransaction.hide(mSelectedFragment!!)
            }else{
                A35Log.v(mClassTag, "hideCurrentFlag = false, removing current fragment $mSelectedFragment")
                fragmentTransaction.remove(mSelectedFragment!!)
            }
        }else{
            A35Log.v(mClassTag, "Fragment is already visible")
        }
    }else if(mSelectedFragment == null){
        A35Log.v(mClassTag,"mSelectedFragment = null, so replacing active fragment with new one ${fragment.javaClass.simpleName}")
        fragmentTransaction.replace(R.id.fragPlaceholder, fragment)
    }else{
        A35Log.v(mClassTag, "Fragment is not added, so adding to the screen ${fragment.javaClass.simpleName}")
        fragmentTransaction.add(R.id.fragPlaceholder, fragment)
        if(hideCurrentFrag) {
            A35Log.v(mClassTag, "hideCurrentFlag = true, hiding current fragment $mSelectedFragment")
            fragmentTransaction.hide(mSelectedFragment!!)
        }else{
            A35Log.v(mClassTag, "hideCurrentFlag = false, removing current fragment $mSelectedFragment")
            fragmentTransaction.remove(mSelectedFragment!!)
        }
    }

    A35Log.v(mClassTag, "committing swap fragment transaction")
    fragmentTransaction.commit()
    A35Log.v(mClassTag, "mSelectedFragment = ${fragment.javaClass.simpleName}")
    mSelectedFragment = fragment
}

所有示例均在Kotlin中提供,因为这是Android的发展方向,如果您尚未使用Android,则应该使用Kotlin而不是Java进行学习。如果您使用Java,则可以将其粘贴到Java文件中,我相信它将为您提供将其转换为Java的功能。

快乐编码!

答案 1 :(得分:0)

这最终为我解决了:

    private fun updateUI(user: FirebaseUser?) {
        if (user != null) {

//            tvStatus.text = "Google User email: " + user.email!!
//            tvDetail.text = "Firebase User ID: " + user.uid

            var fragment = supportFragmentManager.findFragmentByTag("setting") as SettingFragment
            fragment.changeVisibility(true)
//            btn_sign_in.visibility = View.GONE
//            layout_sign_out_and_disconnect.visibility = View.VISIBLE
        } else {
//            tvStatus.text = "Signed Out"
//            tvDetail.text = null
            var fragment = supportFragmentManager.findFragmentByTag("setting") as SettingFragment
            fragment.changeVisibility(false)
//            btn_sign_in.visibility = View.VISIBLE
//            layout_sign_out_and_disconnect.visibility = View.GONE
        }
    }