如何使用Android Kotlin实施类似于YouTube和Instagram的适当导航

时间:2019-09-01 08:29:10

标签: android kotlin bottomnavigationview fragment-backstack android-jetpack-navigation

我在应用程序中难以实现适当的导航结构。我希望它的行为类似于YouTube和Instagram中的导航。我遇到的最大问题是与堆栈和碎片娱乐有关。

我目前正在使用具有多个片段的单一活动方法。我在主活动中有一个应用程序栏和底部导航视图,其中包含3个菜单项。应用程序栏上有一个菜单项,该菜单项在被选中时可导航到用户个人资料片段,而底部导航栏的每个菜单项在被选择时均可导航到不同的根片段(家庭,搜索和个人资料)。我还使用Google的firebase数据库和firestore来存储用户数据(电子邮件,uid,密码等)和照片。

我尝试过使用supportFragmentManager.beginTransaction()。replace方式和android jetpack的导航架构,但是都无法产生我需要的结果。

我能够使用supportFragmentManager方法导航到正确的目的地,但是似乎无法实现正确的向后导航结构。我试图找到实现此目的的其他代码示例,但是找不到任何有效的方法,并且这些示例中有很多都是Java代码中使用较旧方法的较旧版本,这在尝试转换为kotlin代码时很困难。

jetpack导航组件更易于使用,但我也无法使其正常运行。据我所知,当前的导航不支持多个堆栈,并且没有适当的向后导航结构,除非您添加此处提供的NavigationExtensions文件:https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample。使用此示例,我遇到以下问题:

1。向后导航不会返回原始保存的片段状态,而是重新创建一个全新的片段。

2。从应用程序栏导航到个人资料片段是可行的,但是当用户位于片段中并再次按下时会崩溃。

3。在底部导航视图中,将一组默认参数传递给用户片段项目菜单。我最初将帐户配置文件片段绑定到底部的导航菜单项(出于测试目的仍然这样做),并且将登录用户的uid设置为默认参数。使用的fragment(UserFragment)采用uid参数,并使用它从Google的firebase中获取适当的信息。我以前可以通过使用常规的jetpack导航组件(不带高级示例)并在MainActivity中添加以下代码来实现此目的:

val navArgument1 = NavArgument.Builder().setDefaultValue(uid).build()
val orderDestination = navController.graph.findNode(R.id.user_Fragment)
orderDestination?.addArgument("destinationUid",navArgument1)

然后在用户片段中,我使用以下代码获取正确的uid:

uid = arguments?.getString("destinationUid")

使用高级示例导航组件,我无法将此默认参数传递给用户片段。我不断收到类似“没有与此片段关联的导航控制器”之类的错误,并且应用程序崩溃。

主要活动

class ExploreActivity : AppCompatActivity(),BottomNavigationView.OnNavigationItemSelectedListener{

    override fun onNavigationItemSelected(p0:MenuItem):Boolean{

        when(p0.itemId){
            R.id.home->{
                val homeViewFragment = HomeViewFragment()
                supportFragmentManager.beginTransaction().replace(R.id.nav_host_fragment,homeViewFragment).commit()
                return true
            }
            R.id.world->{
                val publicViewFragment = PublicViewFragment()
                supportFragmentManager.beginTransaction().replace(R.id.nav_host_fragment,publicViewFragment).commit()
                return true
            }
            R.id.account->{
                val userFragment = UserFragment()
                val bundle = Bundle()
                val uid=FirebaseAuth.getInstance().currentUser?.uid

                bundle.putString("destinationUid",uid)
                userFragment.arguments=bundle

                supportFragmentManager.beginTransaction().replace(R.id.nav_host_fragment,userFragment).commit()
                return true
            }
        }
        return false
    }


    override fun onCreate(savedInstanceState:Bundle?){
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_explore)

        bottom_navigation_explore.setOnNavigationItemSelectedListener(this)
        bottom_navigation_explore.selectedItemId=R.id.home

    }

    override fun onActivityResult(requestCode:Int,resultCode:Int,data:Intent?){
        super.onActivityResult(requestCode,resultCode,data)

        if(requestCode==UserFragment.PICK__PROFILE_FROM_ALBUM&&resultCode==Activity.RESULT_OK){
            val imageUri=data?.data
            val uid=FirebaseAuth.getInstance().currentUser?.uid
            val storageRef=FirebaseStorage.getInstance().reference.child("userProfileImages")
                .child(uid!!)

            storageRef.putFile(imageUri!!).continueWithTask{task:Task<UploadTask.TaskSnapshot>->
                return@continueWithTask storageRef.downloadUrl
            }.addOnSuccessListener{uri->
                val map=HashMap<String,Any>()
                map["image"]=uri.toString()
                FirebaseFirestore.getInstance().collection("profileImages").document(uid).set(map)
            }
        }
    }
}

用户片段

class UserFragment : Fragment(){

    var fragmentView : View? = null
    var firestore : FirebaseFirestore? = null
    var uid : String? = null
    var auth : FirebaseAuth? = null
    var currentUserUid : String? = null

    companion object{
        var PICK__PROFILE_FROM_ALBUM = 10
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        fragmentView = LayoutInflater.from(activity).inflate(R.layout.activity_main,container,false)

        uid = arguments?.getString("destinationUid")
        firestore = FirebaseFirestore.getInstance()
        auth = FirebaseAuth.getInstance()
        currentUserUid = auth?.currentUser?.uid

        return fragmentView
        }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        if(uid == currentUserUid) {

            fragmentView?.btn_follow_signout_main?.text = "Signout"
            fragmentView?.btn_follow_signout_main?.setOnClickListener {
                activity?.finish()
                startActivity(Intent(activity, LoginActivity::class.java))
                auth?.signOut()
            }
            requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),1)

            iv_createpost_main.setOnClickListener {
                if (ContextCompat.checkSelfPermission(context!!, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){

                    startActivity(Intent(activity,CreatePost::class.java))
                }
                return@setOnClickListener
            }

            //add explanation of why permission is needed
            if (ContextCompat.checkSelfPermission(context!!, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                iv_profilepicture_main.setOnClickListener {

                    val intent = Intent(Intent.ACTION_PICK)
                    intent.type = "image/*"
                    activity?.startActivityForResult(intent, PICK__PROFILE_FROM_ALBUM)
                }
            }
        }
                    else{
            fragmentView?.btn_follow_signout_main?.text = "Follow +"
            fragmentView?.btn_follow_signout_main?.setOnClickListener {
                requestFollow()
            }
        }


        getProfileImage()
        getUserName()
    }

    private fun getProfileImage() {

        firestore?.collection("profileImages")!!.document(uid!!).get().addOnCompleteListener { task ->
            if(task.isSuccessful){
                val url = task.result!!["image"]
                if(url != null){
                    Glide.with(activity!!).load(url).into(iv_profilepicture_main)
                }
                else{
                    iv_profilepicture_main.setImageResource(R.drawable.ic_account)
                }
            }
        }
    }

    private fun getUserName(){
        firestore?.collection("users")!!.document(uid!!).get().addOnCompleteListener { task ->
            if(task.isSuccessful){
                val username = task.result!!["username"]
                if(username != null){
                    activity?.setTitle("" + username)
                }
            }
        }
    }

        }


我的项目当前是使用支持片段管理器进行设置的,但是我一直在使用它和导航组件之间来回尝试以使事情正常进行。

我还有其他两个片段与底部导航相关联,但是我只包含了相关代码,我认为这是我的问题所在。其他两个片段都有一个用户个人资料图片,单击该用户时,它将用户导航到所选个人资料。这些交易没有任何问题,因为我可以轻松地使用setOnClickListener方法应用捆绑包和参数。

TL; DR

总结所有内容:我正在寻找一种在整个应用程序中实施适当导航流程的方法。我遇到向后导航的问题,并且在不应该重新创建片段时遇到问题。我曾尝试使用片段管理器和android jetpack导航组件,但都没有运气。如果有任何人有关于如何使用android kotlin和最新方法实现此目的的信息,并且想分享,我将不胜感激。

谢谢。

0 个答案:

没有答案