본문 바로가기

Android

RecyclerView에 데이터 추가하기 (Fragment, ViewPager2)

Q : FAB를 눌러서 Todo 추가 화면을 노출 시키고, 제목과 내용을 입력해서 “Todo” 탭에 반영

 

1. requireActivity() 사용

MainActivity

  • fabAdd 버튼 눌러 TodoActivity로 이동
class MainActivity : AppCompatActivity() {

    private lateinit var binding: MainActivityBinding

    private val viewPagerAdapter by lazy {
        MainViewPagerAdapter(this)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = MainActivityBinding.inflate(layoutInflater)
        setContentView(binding.root)

        initView()

    }

    private fun initView() = with(binding) {
        toolBar.title = getString(R.string.app_name)

        viewPager.adapter = viewPagerAdapter

        // FloatingActionButton 숨기기
        viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                // 페이지가 선택되었을 때 호출됩니다.
                super.onPageSelected(position)
                if(position == 0){
                    binding.fabAddTodo.show()
                }else{
                    binding.fabAddTodo.hide()
                }
            }
        })

        // TabLayout x ViewPager2
        TabLayoutMediator(tabLayout, viewPager) { tab, position ->
            tab.setText(viewPagerAdapter.getTitle(position))
        }.attach()

        // fab
        fabAddTodo.setOnClickListener {
            val intent = Intent(it.context, TodoAddActivity::class.java)
            startActivity(intent)
        }

    }
}

 

TodoAddActivity

  • 입력받은 제목과 내용 데이터를 MainActivity로 보냄
class TodoAddActivity : AppCompatActivity() {

    private lateinit var binding: TodoAddActivityBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = TodoAddActivityBinding.inflate(layoutInflater)
        setContentView(binding.root)

        setSupportActionBar(binding.toolbar2)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        supportActionBar?.title = "할 일"

        binding.toolbar2.setNavigationOnClickListener{
            finish()
        }


        binding.btnAdd.setOnClickListener {
            val title = binding.etTitle.text.toString()
            val content = binding.etContent.text.toString()

            val mainActivityIntent = Intent(this, MainActivity::class.java)
            mainActivityIntent.putExtra("title", title)
            mainActivityIntent.putExtra("content", content)
            startActivity(mainActivityIntent)
            finish()


        }

    }
}

 

TodoFragment

  • requireActivity를 사용해 MainActivity에 전달된 데이터를 Fragment에서도 받아옴 (MainActivity와 연결되어있어 가능)
  • testList 넣은 뒤 어댑터의 addItems 함수로 연결
class TodoFragment : Fragment() {

    companion object {
        const val TAG = "TodoFragment"

        fun newInstance() = TodoFragment()
    }

    private var _binding: TodoFragmentBinding? = null
    private val binding get() = _binding!!

    private val listAdapter by lazy {
        TodoListAdapter()
    }

    val testList = arrayListOf<TodoModel>()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = TodoFragmentBinding.inflate(inflater, container, false)
        return binding.root
    }

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

        // 데이터 가져오기 (MainActivity가 받아온 데이터)
        val titleText = requireActivity().intent.getStringExtra("title")
        val content = requireActivity().intent.getStringExtra("content")
        if (!titleText.isNullOrEmpty()) {
            if (content != null) {
                testList.add(TodoModel(titleText, content))
            }else{
                testList.add(TodoModel(titleText, ""))
            }
        }

        listAdapter.addItems(testList)
    }

    private fun initView() = with(binding) {
        todoList.adapter = listAdapter
    }

    override fun onDestroyView() {
        _binding = null
        super.onDestroyView()
    }
}

 

TodoListAdapter

  • 받아온 리스트를 Adapter용 list에 추가
  • notifyDataSetChanged()를 통해 새롭게 업데이트된 데이터 보여줌
private val list = ArrayList<TodoModel>()

class TodoListAdapter : RecyclerView.Adapter<TodoListAdapter.ViewHolder>() {

    fun addItems(items: List<TodoModel>) {
        list.addAll(items)
        notifyDataSetChanged()
    }

    override fun getItemCount(): Int {
        return list.size
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            TodoItemBinding.inflate(LayoutInflater.from(parent.context))
        )
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = list[position]
        holder.bind(item)
    }

    class ViewHolder(
        private val binding: TodoItemBinding
    ) : RecyclerView.ViewHolder(binding.root) {

        fun bind(item: TodoModel) = with(binding) {
            title.text = item.title
            content.text = item.content
        }
    }

}

 

TodoModel

data class TodoModel(
    val title: String,
    val content: String,
)

 

 

 

2. registerForActivityResult, MainActivityAdapter에서 Fragment 가져오기

MainActivity

  • fabAdd 버튼 눌러 TodoActivity로 이동
  • registerForActivityResult 사용해 데이터 받아오기
class MainActivity : AppCompatActivity() {

    private lateinit var binding: MainActivityBinding

    private val viewPagerAdapter by lazy {
        MainViewPagerAdapter(this)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = MainActivityBinding.inflate(layoutInflater)
        setContentView(binding.root)

        initView()

    }

    private fun initView() = with(binding) {
        toolBar.title = getString(R.string.app_name)

        viewPager.adapter = viewPagerAdapter

        //registerForActivityResult 사용해 데이터 받아오기
        val resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
            result ->
            if(result.resultCode == Activity.RESULT_OK){
                val titleText = result.data?.getStringExtra("title").toString()
                val content = result.data?.getStringExtra("content").toString()

                // fragment 받아온 뒤 fragment 함수인 addList 사용
                val todoFragment = viewPagerAdapter.getTodoFragment() as TodoFragment

                if (titleText != null) {
                    if (content != null) {
                        todoFragment.addList(titleText, content) // titleText와 content를 전달하여 호출
                    } else {
                        todoFragment.addList(titleText, "") // titleText만 전달하여 호출
                    }
                }
            }
        }



        // FloatingActionButton 숨기기
        viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                // 페이지가 선택되었을 때 호출됩니다.
                super.onPageSelected(position)
                if(position == 0){
                    binding.fabAddTodo.show()
                }else{
                    binding.fabAddTodo.hide()
                }
            }
        })

        // TabLayout x ViewPager2
        TabLayoutMediator(tabLayout, viewPager) { tab, position ->
            tab.setText(viewPagerAdapter.getTitle(position))
        }.attach()

        // fab
        fabAddTodo.setOnClickListener {
            val intent = Intent(it.context, TodoAddActivity::class.java)
            resultLauncher.launch(intent)
        }

    }
}

 

TodoAddActivity

  • 입력받은 제목과 내용 데이터를 MainActivity로 보냄
class TodoAddActivity : AppCompatActivity() {

    private lateinit var binding: TodoAddActivityBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = TodoAddActivityBinding.inflate(layoutInflater)
        setContentView(binding.root)

        setSupportActionBar(binding.toolbar2)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        supportActionBar?.title = "할 일"

        binding.toolbar2.setNavigationOnClickListener{
            finish()
        }


        binding.btnAdd.setOnClickListener {
            val title = binding.etTitle.text.toString()
            val content = binding.etContent.text.toString()

            // RESULT_OK 결과코드와 데이터 보냄
            intent.putExtra("title", title)
            intent.putExtra("content", content)
            setResult(RESULT_OK, intent)
            finish()
        }

    }
}

 

MainViewPagerAdapter

  • fragments 리스트 순서 0번째인 TodoFragment 리턴
  • TodoFragment 가져오는 함수 이용해 다른 액티비티에서도 TodoFragment를 연결할 수 있다.
class MainViewPagerAdapter(
    fragmentActivity: FragmentActivity
) : FragmentStateAdapter(fragmentActivity) {

    private val fragments = ArrayList<MainTabs>()

    init {
        fragments.add(
            MainTabs(TodoFragment.newInstance(), "Todo")
        )
        fragments.add(
            MainTabs(BookmarkFragment.newInstance(), "Bookmark"),
        )
    }

    //TodoFragment 가져오는 함수
    fun getTodoFragment() : Fragment{
        return fragments[0].fragment
    }

    fun getTitle(position: Int): String {
        return fragments[position].titleRes
    }

    override fun getItemCount(): Int {
        return fragments.size
    }

    override fun createFragment(position: Int): Fragment {
        return fragments[position].fragment
    }
}

 

TodoFragment

  • addList 함수 생성해 listAdapter의 addItems 함수 불러옴
  • addItems 함수 사용해 adapter 안에 있는 list에 새로운 TodoModel 객체 추가 시킴
class TodoFragment : Fragment() {

    companion object {
        const val TAG = "TodoFragment"

        fun newInstance() = TodoFragment()
    }

    private var _binding: TodoFragmentBinding? = null
    private val binding get() = _binding!!

    private val listAdapter by lazy {
        TodoListAdapter()
    }

    val testList = arrayListOf<TodoModel>()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = TodoFragmentBinding.inflate(inflater, container, false)
        return binding.root
    }

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

    }

    //listAdatper의 함수인 addItems 연결해 adapter list에 추가시킴 
    fun addList(title:String, content:String){
        listAdapter.addItems(TodoModel(title, content))
    }

    private fun initView() = with(binding) {
        todoList.adapter = listAdapter
    }

    override fun onDestroyView() {
        _binding = null
        super.onDestroyView()
    }
}

 

TodoFragment

  • 객체를 하나하나 받기 위해 인자 값을 변경해줌
class TodoListAdapter : RecyclerView.Adapter<TodoListAdapter.ViewHolder>() {

    private val list = ArrayList<TodoModel>()

    // 인자 값 변경 : List<TodoModel> -> TodoModel
    fun addItems(items: TodoModel) {
        list.add(items)
        notifyDataSetChanged()
    }

    override fun getItemCount(): Int {
        return list.size
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            TodoItemBinding.inflate(LayoutInflater.from(parent.context))
        )
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = list[position]
        holder.bind(item)
    }

    class ViewHolder(
        private val binding: TodoItemBinding
    ) : RecyclerView.ViewHolder(binding.root) {

        fun bind(item: TodoModel) = with(binding) {
            title.text = item.title
            content.text = item.content
        }
    }

}

 

MainActivity

  • viewPagerAdapter.getTodoFragment() as TodoFragment : TodoFragment 가져오기
  • todoFragment.addList(titleText, content) : titleText와 content를 Fragment에 전달하여 호출
class MainActivity : AppCompatActivity() {

    private lateinit var binding: MainActivityBinding

    private val viewPagerAdapter by lazy {
        MainViewPagerAdapter(this)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = MainActivityBinding.inflate(layoutInflater)
        setContentView(binding.root)

        initView()

    }

    private fun initView() = with(binding) {
        toolBar.title = getString(R.string.app_name)

        viewPager.adapter = viewPagerAdapter

        //registerForActivityResult 사용해 데이터 받아오기
        val resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
            result ->
            if(result.resultCode == Activity.RESULT_OK){
                val titleText = result.data?.getStringExtra("title").toString()
                val content = result.data?.getStringExtra("content").toString()

                // fragment 받아온 뒤 fragment 함수인 addList 사용
                val todoFragment = viewPagerAdapter.getTodoFragment() as TodoFragment

                if (titleText != null) {
                    if (content != null) {
                        todoFragment.addList(titleText, content) // titleText와 content를 전달하여 호출
                    } else {
                        todoFragment.addList(titleText, "") // titleText만 전달하여 호출
                    }
                }
            }
        }



        // FloatingActionButton 숨기기
        viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                // 페이지가 선택되었을 때 호출됩니다.
                super.onPageSelected(position)
                if(position == 0){
                    binding.fabAddTodo.show()
                }else{
                    binding.fabAddTodo.hide()
                }
            }
        })

        // TabLayout x ViewPager2
        TabLayoutMediator(tabLayout, viewPager) { tab, position ->
            tab.setText(viewPagerAdapter.getTitle(position))
        }.attach()

        // fab
        fabAddTodo.setOnClickListener {
            val intent = Intent(it.context, TodoAddActivity::class.java)
            resultLauncher.launch(intent)
        }

    }
}

 

 

 

 

'Android' 카테고리의 다른 글

Fragment  (0) 2023.08.24
뷰 바인딩  (0) 2023.08.24
View와 ViewGroup  (2) 2023.08.10
Recycler View  (0) 2023.08.10
TabLayout과 ViewPager2 연결하기  (0) 2023.08.09