测验项目中如何创建多道拖拽答题题目?是否可采用Fragment实现?
用Fragment实现多道拖拽答题的最佳实践
当然可以用Fragment来实现,而且这绝对是处理多道同类型题目最优雅的方案之一!你已经有了单题的拖拽逻辑,把它封装成Fragment后,不仅能轻松复用,还能让题目管理、状态保存变得更简单。下面是具体的实现步骤:
1. 封装拖拽答题的Fragment模板
首先把你Activity里的拖拽答题逻辑和布局,迁移到一个独立的DragQuizFragment中。关键是让这个Fragment可配置——也就是能接收不同的题目数据(题干、选项、正确答案),这样每个Fragment实例对应一道题。
示例代码(Kotlin):
class DragQuizFragment : Fragment() { private lateinit var questionContent: String private lateinit var optionsList: List<String> private lateinit var correctOption: String // 用静态方法创建Fragment实例并传递参数 companion object { private const val ARG_QUESTION = "arg_question" private const val ARG_OPTIONS = "arg_options" private const val ARG_CORRECT = "arg_correct" fun newInstance(question: String, options: List<String>, correct: String): DragQuizFragment { return DragQuizFragment().apply { arguments = Bundle().apply { putString(ARG_QUESTION, question) putStringArrayList(ARG_OPTIONS, ArrayList(options)) putString(ARG_CORRECT, correct) } } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 从arguments中取出题目数据 arguments?.let { questionContent = it.getString(ARG_QUESTION) ?: "" optionsList = it.getStringArrayList(ARG_OPTIONS) ?: emptyList() correctOption = it.getString(ARG_CORRECT) ?: "" } } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_drag_quiz, container, false) // 初始化拖拽UI和逻辑(就是你原来Activity里的代码,适配Fragment上下文即可) initDragAndDrop(view) return view } private fun initDragAndDrop(view: View) { // 这里放置你的拖拽实现:比如设置题干文本、加载选项、绑定拖拽监听等 // 注意用requireContext()或者view.context代替Activity的this } }
对应的布局fragment_drag_quiz.xml就用你原来Activity里的拖拽布局即可,不需要大改。
2. 在Activity中管理多个Fragment
接下来有两种常用的方式来展示和切换多道题:
方式一:用ViewPager2实现滑动切换(推荐)
如果希望用户能左右滑动切换题目,ViewPager2 + FragmentStateAdapter是最佳选择,它会自动管理Fragment的创建、销毁和状态保存,非常适合多题场景。
示例代码:
class QuizActivity : AppCompatActivity() { private lateinit var viewPager: ViewPager2 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_quiz) // 模拟题目数据(实际可以从本地数据库/网络接口加载) val quizData = listOf( QuizQuestion( question = "把「猫」拖到「动物」分类", options = listOf("猫", "桌子", "书本"), correctAnswer = "猫" ), QuizQuestion( question = "把「桌子」拖到「家具」分类", options = listOf("桌子", "狗", "花朵"), correctAnswer = "桌子" ) // 更多题目... ) viewPager = findViewById(R.id.view_pager) viewPager.adapter = QuizPagerAdapter(this, quizData) } } // 题目数据类 data class QuizQuestion(val question: String, val options: List<String>, val correctAnswer: String) // ViewPager2的适配器 class QuizPagerAdapter( fragmentActivity: FragmentActivity, private val quizList: List<QuizQuestion> ) : FragmentStateAdapter(fragmentActivity) { override fun getItemCount(): Int = quizList.size override fun createFragment(position: Int): Fragment { val question = quizList[position] return DragQuizFragment.newInstance(question.question, question.options, question.correctAnswer) } }
方式二:用FragmentManager动态切换
如果不需要滑动,只想通过“上一题/下一题”按钮切换,可以用FragmentTransaction来动态替换容器里的Fragment:
// 在QuizActivity中 private var currentQuestionIndex = 0 private val quizData = listOf(/* 题目数据 */) fun switchToNextQuestion() { if (currentQuestionIndex >= quizData.size - 1) return currentQuestionIndex++ val nextFragment = DragQuizFragment.newInstance( quizData[currentQuestionIndex].question, quizData[currentQuestionIndex].options, quizData[currentQuestionIndex].correctAnswer ) supportFragmentManager.beginTransaction() .replace(R.id.quiz_container, nextFragment) .addToBackStack(null) // 可选,用于返回上一题 .commit() }
3. 保存答题状态
如果需要记录用户每道题的答题结果,可以用ViewModel来共享数据——因为ViewModel的生命周期和Activity绑定,不会因为Fragment的销毁重建而丢失数据。
示例:创建一个QuizViewModel,让每个Fragment在用户完成答题后,把结果传到ViewModel中:
class QuizViewModel : ViewModel() { private val _answers = mutableMapOf<Int, String>() // key是题目索引,value是用户答案 val answers: Map<Int, String> get() = _answers fun saveAnswer(questionIndex: Int, answer: String) { _answers[questionIndex] = answer } }
在Fragment中获取ViewModel并保存答案:
val viewModel = ViewModelProvider(requireActivity())[QuizViewModel::class.java] // 用户完成拖拽后调用 viewModel.saveAnswer(position, userSelectedAnswer)
为什么用Fragment这么合适?
- 复用性极强:只需要写一次拖拽逻辑,所有同类型题目都能复用这个Fragment,后续修改拖拽逻辑也只需要改一处。
- 状态管理方便:Fragment自带生命周期回调,能在页面旋转、后台回收时自动保存状态。
- 扩展性好:以后如果要加其他类型的题目(比如选择题、填空题),只需要创建新的Fragment,和拖拽题Fragment共存即可。
内容的提问来源于stack exchange,提问作者John vattic
相关产品推荐
相关产品推荐

