2021年2月25日木曜日

ViewPager2 でページを動的に追加・削除する

大事なポイントは FragmentStateAdapter を継承した Adapter で getItemId() と containsItem() を実装すること、notifyDataSetChanged() だとうまく動かないので DiffUtil.calculateDiff() を使うことです。
  1. class ViewPager2Activity : AppCompatActivity() {  
  2.   
  3.     private val binding by lazy { ActivityViewPager2Binding.inflate(layoutInflater) }  
  4.   
  5.     override fun onCreate(savedInstanceState: Bundle?) {  
  6.         super.onCreate(savedInstanceState)  
  7.         setContentView(binding.root)  
  8.   
  9.         val list = listOf(  
  10.             PageType.MAIN,  
  11.             PageType.FAVORITE,  
  12.             PageType.SETTING,  
  13.         )  
  14.   
  15.         val list2 = listOf(  
  16.             PageType.MAIN,  
  17.             PageType.SETTING,  
  18.         )  
  19.   
  20.         val adapter = PagerAdapter(list, this)  
  21.         binding.pager.adapter = adapter  
  22.   
  23.         TabLayoutMediator(binding.tabLayout, binding.pager) { tab, position ->  
  24.             tab.text = list[position].toString()  
  25.         }.attach()  
  26.   
  27.         binding.checkbox.setOnCheckedChangeListener { _, isChecked ->  
  28.             adapter.updateList(if (isChecked) list else list2)  
  29.         }  
  30.     }  
  31. }  
  32.   
  33. enum class PageType {  
  34.     MAIN,  
  35.     FAVORITE,  
  36.     SETTING  
  37. }  
  38.   
  39. private class PagerAdapter(  
  40.     initial: List<PageType>,  
  41.     fragmentActivity: FragmentActivity  
  42. ) : FragmentStateAdapter(fragmentActivity) {  
  43.   
  44.     private val list = mutableListOf<PageType>()  
  45.   
  46.     init {  
  47.         list.addAll(initial)  
  48.     }  
  49.   
  50.     override fun getItemCount(): Int {  
  51.         return list.size  
  52.     }  
  53.   
  54.     override fun createFragment(position: Int): Fragment {  
  55.         return PageFragment.newInstance(list[position])  
  56.     }  
  57.   
  58.     override fun getItemId(position: Int): Long {  
  59.         return list[position].ordinal.toLong()  
  60.     }  
  61.   
  62.     override fun containsItem(itemId: Long): Boolean {  
  63.         return list.any { it.ordinal.toLong() == itemId }  
  64.     }  
  65.   
  66.     fun updateList(newList: List<PageType>) {  
  67.         // notifyDataSetChanged() だとうまく動かない  
  68.   
  69.         val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() {  
  70.             override fun getOldListSize(): Int {  
  71.                 return list.size  
  72.             }  
  73.   
  74.             override fun getNewListSize(): Int {  
  75.                 return newList.size  
  76.             }  
  77.   
  78.             override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {  
  79.                 return list[oldItemPosition] == newList[newItemPosition]  
  80.             }  
  81.   
  82.             override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {  
  83.                 return list[oldItemPosition] == newList[newItemPosition]  
  84.             }  
  85.         })  
  86.   
  87.         list.clear()  
  88.         list.addAll(newList)  
  89.   
  90.         diff.dispatchUpdatesTo(this)  
  91.     }  
  92. }  
  93.   
  94. class PageFragment : Fragment() {  
  95.   
  96.     private val color = Color.rgb(Random.nextInt(256), Random.nextInt(256), Random.nextInt(256))  
  97.   
  98.     override fun onCreateView(  
  99.         inflater: LayoutInflater,  
  100.         container: ViewGroup?,  
  101.         savedInstanceState: Bundle?  
  102.     ): View {  
  103.         return TextView(inflater.context).apply {  
  104.             setBackgroundColor(color)  
  105.             text = (requireArguments().getSerializable("type") as PageType).toString()  
  106.         }  
  107.     }  
  108.   
  109.     companion object {  
  110.         fun newInstance(type: PageType): PageFragment {  
  111.             return PageFragment().apply {  
  112.                 arguments = bundleOf("type" to type)  
  113.             }  
  114.         }  
  115.     }  
  116. }  

0 件のコメント:

コメントを投稿