Как изменить вид фрагмента / видимость кнопки из действия? - PullRequest
0 голосов
/ 01 ноября 2018

Как видно из названия, я пытаюсь изменить вид фрагмента / видимость кнопки из действия.

Код фрагмента:

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 голосов
/ 01 ноября 2018

Хорошо, у вас есть пара вопросов, но, пожалуй, лучше, если я просто предоставлю вам подробный пошаговый отчет. Итак, начнем с самого начала.

Итак, сначала выпуск

Вы ссылаетесь не на ту память. Сначала вы помещаете фрагмент в свой 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>

Тогда в Activity вы просто создадите переменную-член и получите к ней доступ:

//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 или соответствующем месте (например, фрагменты переключения ящиков) и заменить его в заполнителе.

Пример:

// Inside 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, и вы должны учиться на Kotlin, а не на Java, если вы этого еще не сделали. Если вы работаете с Java, вы можете вставить это в файл Java, и я думаю, что он предложит вам перевести его на Java.

Счастливого кодирования!

0 голосов
/ 01 ноября 2018

Это решило это для меня в итоге:

    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
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...