从 viewPager 片段 (Kotlin) 获取用户输入信息



我在Android Studio工作,遇到了一个我以前从未遇到过的问题。

我正在制作一个界面,该界面引入 JSON 来创建自定义表单,并创建一系列带有编辑文本和日期选择器等的选项卡控制的片段。这些表格是在网站上创建的;在 JSON 将它们拉入之前,内容是未知的。

我已经设置了一个 SectionPagerAdapter 来处理创建部分和占位符片段以创建各种选取器和编辑文本。我正在使用ViewCompat.generateViewId((自动生成视图ID。

目前,我正在使用模拟 JSON 数据进行测试,一切正常。用户能够输入信息并影响更改;当用户浏览不同的部分选项卡时,更改会持续存在,无论有多少选项卡。

我遇到的问题是在点击浮动操作按钮时尝试从所有片段中获取输入数据。我只是还没有弄清楚如何从活动级别的片段中访问数据。

下面是代码:

创建检查活动

class CreateInspectionActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create_inspection)
//List of items to mock what I would receive as JSON
val mockJSON = JSONArray()
mockJSON.put(Pair("General", arrayListOf(
Pair("General EditText", "editText"), Pair("General Date", "datePicker"),
Pair("General Time", "timePicker"), Pair("General EditText 2", "editText"),
Pair("General Rating", "rating"), Pair("General Rating 2", "rating"),
Pair("General Rating 3", "rating"), Pair("General Rating 4", "rating"),
Pair("General Rating 5", "rating"), Pair("General Rating 6", "rating"),
Pair("General EditText 3", "editText"), Pair("General EditText 4", "editText"),
Pair("General EditText 5", "editText"), Pair("General Date 2", "datePicker"),
Pair("General Rating 7", "rating"), Pair("General Time 2", "timePicker"))))
mockJSON.put(Pair("Secondary", arrayListOf(
Pair("Secondary EditText", "editText"), Pair("Secondary EditText2", "editText"),
Pair("Secondary EditText 3", "editText"), Pair("Secondary Date", "datePicker"),
Pair("Secondary Time", "timePicker"),  Pair("Secondary Rating", "rating"),
Pair("Secondary Rating 2", "rating"), Pair("Secondary Rating 3", "rating"),
Pair("Secondary Rating 4", "rating"), Pair("Secondary Rating 5", "rating"))))
mockJSON.put(Pair("Tertiary", arrayListOf(
Pair("Tertiary Rating", "rating"), Pair("Tertiary Rating 2", "rating"),
Pair("Tertiary Rating 3", "rating"), Pair("Tertiary Rating 4", "rating"),
Pair("Tertiary Rating 5", "rating"), Pair("Tertiary Rating 6", "rating"),
Pair("Tertiary Rating 7", "rating"), Pair("Tertiary Rating 8", "rating"),
Pair("Tertiary Rating 9", "rating"), Pair("Tertiary Rating 10", "rating"))))
mockJSON.put(Pair("Quaternary", arrayListOf(
Pair("Quaternary Rating", "rating"), Pair("Quaternary Rating 2", "rating"),
Pair("Quaternary Rating 3", "rating"), Pair("Quaternary Rating 4", "rating"),
Pair("Quaternary Rating 5", "rating"), Pair("Quaternary Rating 6", "rating"),
Pair("Quaternary Rating 7", "rating"), Pair("Quaternary Rating 8", "rating"),
Pair("Quaternary Rating 9", "rating"), Pair("Quaternary Rating 10", "rating"),
Pair("Quaternary Rating 11", "rating"), Pair("Quaternary Rating 12", "rating"),
Pair("Quaternary Rating 13", "rating"), Pair("Quaternary Rating 14", "rating"),
Pair("Quaternary Rating 15", "rating"), Pair("Quaternary Rating 16", "rating"),
Pair("Quaternary Rating 17", "rating"), Pair("Quaternary Rating 18", "rating"),
Pair("Quaternary Rating 19", "rating"), Pair("Quaternary Rating 20", "rating"))))
mockJSON.put(Pair("Quinary", arrayListOf(
Pair("Quinary Rating", "rating"), Pair("Quinary Rating 2", "rating"),
Pair("Quinary Rating 3", "rating"), Pair("Quinary Rating 4", "rating"),
Pair("Quinary Rating 5", "rating"), Pair("Quinary Rating 6", "rating"),
Pair("Quinary Rating 7", "rating"), Pair("Quinary Rating 8", "rating"),
Pair("Quinary Rating 9", "rating"), Pair("Quinary Rating 10", "rating"),
Pair("Quinary Rating 11", "rating"), Pair("Quinary Rating 12", "rating"),
Pair("Quinary Rating 13", "rating"), Pair("Quinary Rating 14", "rating"),
Pair("Quinary Rating 15", "rating"), Pair("Quinary Rating 16", "rating"),
Pair("Quinary Rating 17", "rating"), Pair("Quinary Rating 18", "rating"),
Pair("Quinary Rating 19", "rating"), Pair("Quinary Rating 20", "rating"))))
mockJSON.put(Pair("Senary", arrayListOf(
Pair("Senary Rating", "rating"), Pair("Senary Rating 2", "rating"),
Pair("Senary Rating 3", "rating"), Pair("Senary Rating 4", "rating"),
Pair("Senary Rating 5", "rating"), Pair("Senary Rating 6", "rating"),
Pair("Senary Rating 7", "rating"), Pair("Senary Rating 8", "rating"),
Pair("Senary Rating 9", "rating"), Pair("Senary Rating 10", "rating"),
Pair("Senary Rating 11", "rating"), Pair("Senary Rating 12", "rating"),
Pair("Senary Rating 13", "rating"), Pair("Senary Rating 14", "rating"),
Pair("Senary Rating 15", "rating"), Pair("Senary Rating 16", "rating"),
Pair("Senary Rating 17", "rating"), Pair("Senary Rating 18", "rating"),
Pair("Senary Rating 19", "rating"), Pair("Senary Rating 20", "rating"))))
mockJSON.put(Pair("Septenary", arrayListOf(
Pair("Septenary Rating", "rating"), Pair("Septenary Rating 2", "rating"),
Pair("Septenary Rating 3", "rating"), Pair("Septenary Rating 4", "rating"),
Pair("Septenary Rating 5", "rating"), Pair("Septenary Rating 6", "rating"),
Pair("Septenary Rating 7", "rating"), Pair("Septenary Rating 8", "rating"),
Pair("Septenary Rating 9", "rating"), Pair("Septenary Rating 10", "rating"),
Pair("Septenary Rating 11", "rating"), Pair("Septenary Rating 12", "rating"),
Pair("Septenary Rating 13", "rating"), Pair("Septenary Rating 14", "rating"),
Pair("Septenary Rating 15", "rating"), Pair("Septenary Rating 16", "rating"),
Pair("Septenary Rating 17", "rating"), Pair("Septenary Rating 18", "rating"),
Pair("Septenary Rating 19", "rating"), Pair("Septenary Rating 20", "rating"))))
mockJSON.put(Pair("Octonary", arrayListOf(
Pair("Octonary Rating", "rating"), Pair("Octonary Rating 2", "rating"),
Pair("Octonary Rating 3", "rating"), Pair("Octonary Rating 4", "rating"),
Pair("Octonary Rating 5", "rating"), Pair("Octonary Rating 6", "rating"),
Pair("Octonary Rating 7", "rating"), Pair("Octonary Rating 8", "rating"),
Pair("Octonary Rating 9", "rating"), Pair("Octonary Rating 10", "rating"),
Pair("Octonary Rating 11", "rating"), Pair("Octonary Rating 12", "rating"),
Pair("Octonary Rating 13", "rating"), Pair("Octonary Rating 14", "rating"),
Pair("Octonary Rating 15", "rating"), Pair("Octonary Rating 16", "rating"),
Pair("Octonary Rating 17", "rating"), Pair("Octonary Rating 18", "rating"),
Pair("Octonary Rating 19", "rating"), Pair("Octonary Rating 20", "rating"))))
mockJSON.put(Pair("Nonary", arrayListOf(
Pair("Nonary Rating", "rating"), Pair("Nonary Rating 2", "rating"),
Pair("Nonary Rating 3", "rating"), Pair("Nonary Rating 4", "rating"),
Pair("Nonary Rating 5", "rating"), Pair("Nonary Rating 6", "rating"),
Pair("Nonary Rating 7", "rating"), Pair("Nonary Rating 8", "rating"),
Pair("Nonary Rating 9", "rating"), Pair("Nonary Rating 10", "rating"),
Pair("Nonary Rating 11", "rating"), Pair("Nonary Rating 12", "rating"),
Pair("Nonary Rating 13", "rating"), Pair("Nonary Rating 14", "rating"),
Pair("Nonary Rating 15", "rating"), Pair("Nonary Rating 16", "rating"),
Pair("Nonary Rating 17", "rating"), Pair("Nonary Rating 18", "rating"),
Pair("Nonary Rating 19", "rating"), Pair("Nonary Rating 20", "rating"))))
//Setup Adapter for different tabs
//This creates the pager adapter with the mock JSON array to create a section tab for each,
// and to send the associated information on to the Placeholder fragment
//Setup adapter for view pager
val sectionsPagerAdapter = SectionsPagerAdapter(this, supportFragmentManager, mockJSON)
val viewPager: ViewPager = findViewById(R.id.view_pager)
//Set this page limit to keep data across multiple tabs. This must be set to the number of tabs there'll be, minus 1
viewPager.offscreenPageLimit = mockJSON.length()-1
viewPager.adapter = sectionsPagerAdapter
//Use view pager to populate tabs
val tabs: TabLayout = findViewById(R.id.tabs)
tabs.setupWithViewPager(viewPager)
val fab: FloatingActionButton = findViewById(R.id.fab)
fab.setOnClickListener { view ->
//TODO: Get data from all the fragments
for(item in 0 until viewPager.childCount) {
Log.d("BEAU", "${viewPager.getChildAt(item)}")
//val child: View = viewPager.getChildAt(item)
}
}
}
}

部分寻呼机适配器

class SectionsPagerAdapter(private val context: Context, fm: FragmentManager, private val mockJSON: JSONArray) : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getItem(position: Int): Fragment {
val jsonList = arrayListOf<Pair<String, ArrayList<String>>>()
for(i in 0 until mockJSON.length()){
@Suppress("unchecked_cast")
jsonList.add(mockJSON[i] as Pair<String, ArrayList<String>>)
}
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below)
return PlaceholderFragment.newInstance(position + 1, jsonList[position].second)
}
override fun getPageTitle(position: Int): CharSequence? {
//Sort through the JSON and get a list of sections.
// Then, create tabs based on those sections
val jsonList = arrayListOf<Pair<String, ArrayList<String>>>()
for(i in 0 until mockJSON.length()){
@Suppress("unchecked_cast")
jsonList.add(mockJSON[i] as Pair<String, ArrayList<String>>)
}
val sectionArray = arrayListOf<String>()
//Get the various sections from mockJSONArray
for (arrayItem in jsonList) {
sectionArray.add(arrayItem.first)
}
return sectionArray[position]
}
override fun getCount(): Int {
//Sort through the JSON and get a list of sections.
// Then, create tabs based on those sections
val jsonList = arrayListOf<Pair<String, ArrayList<String>>>()
for(i in 0 until mockJSON.length()){
@Suppress("unchecked_cast")
jsonList.add(mockJSON[i] as Pair<String, ArrayList<String>>)
}
val sectionArray = arrayListOf<String>()
//Get the various sections from mockJSONArray
for (arrayItem in jsonList) {
sectionArray.add(arrayItem.first)
}
// Show total pages in relation to size of tab titles array.
return sectionArray.size
}
}

占位符片段

class PlaceholderFragment : Fragment() {
private lateinit var pageViewModel: PageViewModel
private val viewIDArrayList = arrayListOf<Int>()
private lateinit var fragmentActivity: FragmentActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
fragmentActivity = activity!!
pageViewModel = ViewModelProviders.of(this).get(PageViewModel::class.java).apply {
setIndex(arguments?.getInt(ARG_SECTION_NUMBER) ?: 1)
}
}
override fun onDestroyView() {
super.onDestroyView()
Log.d("BEAU", "View Destroyed!")
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val root = inflater.inflate(R.layout.fragment_tab_test, container, false)
val textView: TextView = root.findViewById(R.id.section_label)
//Set page title with information gained from putInt in newInstance function below
pageViewModel.text.observe(this, Observer<String> {
textView.text = it
})
//get JSON data from bundle
@Suppress("unchecked_cast")
val jsonData = arguments!!.getStringArrayList("JSONData") as ArrayList<Pair<String, String>>
fun createEditTextLine(titleString: String) {
val verticalLayout = root.findViewById<LinearLayout>(R.id.createInspectionBodyLinearLayout)
val layoutInflater = LayoutInflater.from(fragmentActivity)
val linearLayout = layoutInflater.inflate(R.layout.template_edit_text, null) as LinearLayout
verticalLayout.addView(linearLayout)
val titleText = linearLayout.findViewById<TextView>(R.id.editTextTitle)
titleText.id = ViewCompat.generateViewId()
viewIDArrayList.add(titleText.id)
titleText.text = titleString
//if the number is even, color it differently to make the sections easier to differentiate
if (titleText.id % 2 == 0) {
linearLayout.setBackgroundColor(Color.parseColor("#F2F2F0"))
}
}
fun createDatePickerLine(titleString: String) {
val horizontalLayout = root.findViewById<LinearLayout>(R.id.createInspectionBodyLinearLayout)
val layoutInflater = LayoutInflater.from(fragmentActivity)
val linearLayout = layoutInflater.inflate(R.layout.template_date_picker, null) as LinearLayout
horizontalLayout.addView(linearLayout)
val dateTitle = linearLayout.findViewById<TextView>(R.id.dateTitle)
dateTitle.id = ViewCompat.generateViewId()
dateTitle.text = titleString
viewIDArrayList.add(dateTitle.id)
//if the number is even, color it differently to make the sections easier to differentiate
if (dateTitle.id % 2 == 0) {
linearLayout.setBackgroundColor(Color.parseColor("#F2F2F0"))
}
}
fun createTimePickerLine(titleString: String) {
val horizontalLayout = root.findViewById<LinearLayout>(R.id.createInspectionBodyLinearLayout)
val layoutInflater = LayoutInflater.from(fragmentActivity)
val linearLayout = layoutInflater.inflate(R.layout.template_time_picker, null) as LinearLayout
horizontalLayout.addView(linearLayout)
val timeTitle = linearLayout.findViewById<TextView>(R.id.timeTitle)
timeTitle.id = ViewCompat.generateViewId()
timeTitle.text = titleString
viewIDArrayList.add(timeTitle.id)
//if the number is even, color it differently to make the sections easier to differentiate
if (timeTitle.id % 2 == 0) {
linearLayout.setBackgroundColor(Color.parseColor("#F2F2F0"))
}
}
fun createRatingBarLine(titleString: String) {
val horizontalLayout = root.findViewById<LinearLayout>(R.id.createInspectionBodyLinearLayout)
val layoutInflater = LayoutInflater.from(fragmentActivity)
val linearLayout = layoutInflater.inflate(R.layout.template_rating_bar, null) as LinearLayout
horizontalLayout.addView(linearLayout)
val ratingTitle = linearLayout.findViewById<TextView>(R.id.ratingTitle)
ratingTitle.id = ViewCompat.generateViewId()
ratingTitle.text = titleString
viewIDArrayList.add(ratingTitle.id)
//if the number is even, color it differently to make the sections easier to differentiate
if (ratingTitle.id % 2 == 0) {
linearLayout.setBackgroundColor(Color.parseColor("#F2F2F0"))
}
}
for (item in jsonData) {
if (item.second == "editText") {
createEditTextLine(item.first)
}
if (item.second == "datePicker") {
createDatePickerLine(item.first)
}
if (item.second == "timePicker") {
createTimePickerLine(item.first)
}
if (item.second == "rating") {
createRatingBarLine(item.first)
}
}
return root
}
companion object {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private const val ARG_SECTION_NUMBER = "section_number"
/**
* Returns a new instance of this fragment for the given section
* number.
*/
@JvmStatic
fun newInstance(sectionNumber: Int, jsonForThisSection: ArrayList<String>): PlaceholderFragment {
return PlaceholderFragment().apply {
arguments = Bundle().apply {
putInt(ARG_SECTION_NUMBER, sectionNumber)
putStringArrayList("JSONData", jsonForThisSection)
}
}
}
}
}

页面视图模型

class PageViewModel : ViewModel() {
private val _index = MutableLiveData<Int>()
val text: LiveData<String> = Transformations.map(_index) {
"Hello world from section: $it"
}
fun setIndex(index: Int) {
_index.value = index
}
}

任何帮助将不胜感激。

编辑:正在尝试按照@EpicPandaForce的建议使用共享视图模型。如果有人有具体的想法,请告诉我。

从位置获取片段,然后调用fun getInputData()...函数以检索您的数据.. 但由于adapter.getItem(position)将重新实例化您的碎片, 您可能需要将片段引用放入地图中,然后,当您可以根据位置检索数据时。前任:

占位符片段类假设我们有一个fun getInputData()....

部分寻呼适配器类:

private val fragmentsRef = mutableMapOf<Int, PlaceholderFragment>()

更新getItem

override fun getItem(position: Int): Fragment {
...
val frag = PlaceholderFragment.newInstance(position + 1, jsonList[position].second)
//Here we save a reference of the instantiated fragment
fragmentsRef[position] = frag
return frag
}

然后,删除片段onDestroyItem

override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
super.destroyItem(container, position, `object`)
fragmentsRef.remove(position)
}

当您需要特定位置的片段时,请调用getFragmentAt:

fun getFragmentAt(position: Int): PlaceholderFragment? = fragmentsRef[position]

最后,在浮动操作按钮上单击:

fab.setOnClickListener { view ->
for (item in 0 until viewPager.childCount) {
val frag = sectionsPagerAdapter.getFragmentAt(item)
val data = frag?.getInputData()
...
}
}

像这样使用共享视图模型:

活动:

private lateinit viewModel: PageViewModel
public fun onCreate(..){
viewModel = ViewModelProviders.of(this)[PageViewModel::class.java]
viewModel.observeNewData().observe(this, Observer {
Log.d("Hello","Fetched data - $it")
// do whatever you wish to with this data
})
}

页面视图模型

class PageViewModel : ViewModel() {
private val data = MutableLiveData<MutableList<Pair>>()
// this is to trigger fragments into collecting data
private val triggerCollection = MutableLiveData<Void>() 
// this is to check if all data from all the fragments have been received
private var fragmentCount = 0; 
init {
data  = ArrayList();
}
public observeTriggerCollection() : LiveData<Void> = triggerCollection
public observeNewData() : LiveData<MutableList<Pair>> = data
public fun fetchData(){
fragmentCount = 0
data.value?.clear()
triggerCollection.value = null // this will trigger collection code in fragments
}
public onDataFetched(list : MutableList<Pair>){
data.value?.addAll(list)
fragmentCount++;
if(fragmentCount >= x) //x is the number of fragments/tabs from which data has to be collected
data.value = data.value // to trigger activity function
}
}

在每个片段中:

private var viewModel : PageViewModel? = null
public fun onCreateView(...){
// This will give the instance of viewModel of the activity
viewModel = activity?.let { ViewModelProviders.of(it)[PageViewModel::class.java] }
viewModel?.observeTriggerCollection()?.observe(this, Observer {
val data MutableList<Pair> = ArrayList() 
// collect data here and add it to the above list
viewModel?.onDataFetched(data)
})
}

最新更新