简体   繁体   English

页面数未知或动态的 ViewPager

[英]ViewPager with unknown or dynamic number of pages

I am trying to develop a Survey application for Android.我正在尝试为 Android 开发一个调查应用程序。 In the requirements, the client is asking for a swipe effect between the questions.在需求中,客户要求在问题之间产生滑动效果。 I used a ViewPager with FragmentPagerAdapter and everything works fine.我将ViewPagerFragmentPagerAdapter一起使用,一切正常。

The problem comes when they require a Tree Decision System .当他们需要树决策系统时,问题就来了。 In other words, when the surveyed person select an answer, I should lead him to a question according on which one is defined in that answer.换句话说,当被调查者 select 给出答案时,我应该引导他提出一个问题,根据该答案中定义的哪个问题。

树决策系统

As you can see in the image, before answer the first question, I can't load the second page because I don't know which will be the question to load.如图所示,在回答第一个问题之前,我无法加载第二页,因为我不知道要加载哪个问题。

Also I can't know the number of pages that should I return in the getCount method, only when the user responds, I can know if there's one more page or not, and which should be its content.我也不知道在getCount方法中应该返回多少页,只有当用户响应时,我才能知道是否还有一页,应该是它的内容。


I tried many solution posted over there, but the most important, or at least was logic for me.我尝试了许多在那里发布的解决方案,但最重要的,或者至少对我来说是逻辑。 Is to set the count as the known pages number, and when the user select an answer, I tried to change the count and call notifyDataSetChanged method, but all what I get, is to change the number of pages dynamically, but not the content.是将计数设置为已知页数,当用户 select 回答时,我尝试更改计数并调用notifyDataSetChanged方法,但我得到的只是动态更改页数,而不是内容。

The scenario is:场景是:

  • In the first question, I set the count to 1, so the user can't swipe to the next page because it's unknown.在第一个问题中,我将计数设置为 1,因此用户无法滑动到下一页,因为它是未知的。

  • When the user select an answer, I change the count to 2 and load the next question.当用户 select 回答时,我将计数更改为 2 并加载下一个问题。 Everything OK!一切还好!

  • If the user back to the first question and change his answer, I tried to destroy or change the content of the second page.如果用户回到第一个问题并改变了他的答案,我试图破坏或改变第二页的内容。 But in this case, the notifyDataSetChanged doesn't replace the Fragment .但在这种情况下, notifyDataSetChanged不会替换Fragment

I know that I am asking a strange and difficult behavior, but I want to know if someone has to do the same thing and could find the right solution.我知道我在问一个奇怪而困难的行为,但我想知道是否有人必须做同样的事情并且可以找到正确的解决方案。

Sorry for don't post any code, but after so many intents, my code becomes ugly and I do revert in VCS.很抱歉没有发布任何代码,但是经过这么多意图之后,我的代码变得难看,我确实在 VCS 中恢复了。

You could try a linked list for your data items.您可以尝试为您的数据项创建一个链接列表。 Here's a quick example of how that might look.这是一个简单的示例,说明它的外观。

var viewPager: ViewPager? = null

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_dynamic_view_pager, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    viewPager = view.findViewById(R.id.viewPager)
    viewPager?.apply {
        adapter = MyAdapter(childFragmentManager, this).also {
            it.initialDataItem = buildDataItems()
        }
    }

}

fun buildDataItems(): DataItem {
    val item0 = DataItem(0).also {
        it.title = "What can I help you with today?"
    }
    val item1 = DataItem(1).also {
        it.title = "Technical Problem"
    }
    val item2 = DataItem(2).also {
        it.title = "Ordering Problem"
    }
    val item3 = DataItem(3).also {
        it.title = "Is your power light on?"
    }
    val item4 = DataItem(4).also {
        it.title = "Have you received your order?"
    }
    val item5 = DataItem(5).also {
        it.title = "New content node"
    }
    val item6 = DataItem(6).also {
        it.title = "New content node"
    }

    item0.yesItem = item1
    item0.noItem = item2
    item1.yesItem = item3
    item2.yesItem = item4
    item3.yesItem = item5
    item3.noItem = item6

    return item0
}

data class DataItem(
    var id: Int = 0
) {
    var title: String = ""
    var yesItem: DataItem? = null
    var noItem: DataItem? = null
    var answer: Answer = Answer.UNANSWERED
}

enum class Answer {
    UNANSWERED,
    YES,
    NO
}

class MyAdapter(fm: FragmentManager, val viewPager: ViewPager) : FragmentPagerAdapter(fm) {
    var initialDataItem: DataItem = DataItem()


    override fun getItem(position: Int): Fragment {
        var index = 0
        var dataItem: DataItem? = initialDataItem
        while (index < position) {
            when (dataItem?.answer) {
                Answer.YES -> dataItem = dataItem.yesItem
                Answer.NO -> dataItem = dataItem.noItem
                else -> {}
            }
            index ++
        }

        return DetailFragment(dataItem) {
            dataItem?.answer = if (it) Answer.YES else Answer.NO
            notifyDataSetChanged()
            viewPager.setCurrentItem(position + 1, true)
        }
    }

    override fun getCount(): Int {
        var count = 1
        var dataItem: DataItem? = initialDataItem
        while (dataItem?.answer != Answer.UNANSWERED) {
            when (dataItem?.answer) {
                Answer.YES -> dataItem = dataItem.yesItem
                Answer.NO -> dataItem = dataItem.noItem
                else -> {}
            }
            count++
        }

        return count
    }
}

class DetailFragment(val dataItem: DataItem?, val listener: ((answeredYes: Boolean) -> Unit)) : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_viewpager_detail, container, false)

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

        view.findViewById<TextView>(R.id.title)?.text = dataItem?.title
        view.findViewById<Button>(R.id.yesButton)?.setOnClickListener {
            listener(true)
        }
        view.findViewById<Button>(R.id.noButton)?.setOnClickListener {
            listener(false)
        }
    }
}

Note: You will want to refine this a bit to handle error cases and reaching the end of the tree.注意:您需要稍微改进一下以处理错误情况并到达树的末尾。 Also, you'll want to use a better method for injecting data into the detail fragment - this is just for illustration purposes.此外,您需要使用更好的方法将数据注入细节片段 - 这仅用于说明目的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM