Home > Enterprise >  ViewGroup.addview() is working but child view is not showing
ViewGroup.addview() is working but child view is not showing

Time:06-23

I develop an android app. I want to add TextView(s) to a LinearLayout dynamically. No error occurred but TextView is not showing. I thought sleep_records_container' height might be 0dp and I tried to set 300dp but nothing showed in this container. How do I solve this problem?

Below Fragment is aim to show sleep records in one month.

SleepRecordFragment.kt

package com.example.sleeprecorder.sleeprecord

import android.annotation.SuppressLint

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.view.size
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.example.sleeprecorder.R
import com.example.sleeprecorder.database.SleepRecorderDatabase
import com.example.sleeprecorder.databinding.FragmentSleepRecordBinding
import java.text.SimpleDateFormat
import java.util.*

class SleepRecordFragment: Fragment() {
    @SuppressLint("SimpleDateFormat")
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        Log.i("SleepRecordFragment", "onCreateView called")
        val binding = FragmentSleepRecordBinding.inflate(inflater, container, false)
        //val binding : FragmentSleepRecordBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_sleep_record, container, false)

        val application = requireNotNull(this.activity).application
        val dataSource = SleepRecorderDatabase.getInstance(application).sleepRecordDao

        val viewModelFactory = SleepRecordViewModelFactory(dataSource, application)

        val sleepRecordViewModel = ViewModelProvider(this, viewModelFactory).get(SleepRecordViewModel::class.java)





        binding.sleepRecordViewModel = sleepRecordViewModel
        binding.setLifecycleOwner(this)

        sleepRecordViewModel.oneMonthSleepRecords.observe(this, Observer { oneMonthSleepRecords ->
            Log.i("SleepRecordFragment", "oneMonthSleepRecords.size: ${oneMonthSleepRecords.size}")

            binding.sleepRecordsContainer.removeAllViews()
            oneMonthSleepRecords.forEach { sleepRecord ->
                Log.i("SleepRecordFragment", "Observe oneMonthSleepRecords: ${sleepRecord.toString()}")



                val startSleepTextView = TextView(context)
                startSleepTextView.width = LayoutParams.WRAP_CONTENT
                startSleepTextView.height = LayoutParams.WRAP_CONTENT
                val startSleepDate = Date(sleepRecord!!.startTimeMilli)
                val formatter = SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
                val startSleepText = getString(R.string.start_sleep_datetime, formatter.format(startSleepDate))
                startSleepTextView.text = startSleepText
                Log.i("SleepRecordFragment", "start sleep text: ${startSleepText}")

                val sleepRecordLinearLayout = LinearLayout(context)
                sleepRecordLinearLayout.orientation = LinearLayout.VERTICAL
                sleepRecordLinearLayout.addView(startSleepTextView)
                binding.sleepRecordsContainer.addView(sleepRecordLinearLayout)

            }

            Log.i("SleepRecordFragment", "size in sleep record container: ${binding.sleepRecordsContainer.size}")
        })



        val calendar = Calendar.getInstance()
        val thisYear = calendar.get(Calendar.YEAR)
        val thisMonthIndex = calendar.get(Calendar.MONTH)

        sleepRecordViewModel.setThisYearMonth(thisYear, thisMonthIndex)


        binding.yearMonth.text = getYearMonthStr(thisYear, thisMonthIndex)
        binding.yearMonth.setTag(R.id.year, thisYear)
        binding.yearMonth.setTag(R.id.month_index, thisMonthIndex)
        Log.i("SleepRecordFragment", "tag year: ${binding.yearMonth.getTag(R.id.year)}")
        Log.i("SleepRecordFragment", "tag month index ${binding.yearMonth.getTag(R.id.month_index)}")



        binding.addSleepRecord.setOnClickListener {
            this.findNavController().navigate(SleepRecordFragmentDirections.actionSleepRecordFragmentToAddSleepFragmentRecord())
        }

        binding.goToNextMonth.setOnClickListener {
            val shownYear = binding.yearMonth.getTag(R.id.year).toString().toInt()
            val shownMonthIndex = binding.yearMonth.getTag(R.id.month_index).toString().toInt()
            Log.i("SleepRecordFragment", "shownYear: ${shownYear}")
            Log.i("SleepRecordFragment", "shownMonthIndex: ${shownMonthIndex}")


            val calendarToNextMonth = Calendar.getInstance()
            calendarToNextMonth.set(Calendar.YEAR, shownYear)
            calendarToNextMonth.set(Calendar.MONTH, shownMonthIndex)
            calendarToNextMonth.add(Calendar.MONTH, 1)

            val yearMonthStr = getYearMonthStr(calendarToNextMonth.get(Calendar.YEAR), calendarToNextMonth.get(Calendar.MONTH))


            Log.i("SleepRecordFragment", "next month: ${yearMonthStr}")
            binding.yearMonth.text = yearMonthStr
            binding.yearMonth.setTag(R.id.year, calendarToNextMonth.get(Calendar.YEAR))
            binding.yearMonth.setTag(R.id.month_index, calendarToNextMonth.get(Calendar.MONTH))

            sleepRecordViewModel.onChangeMonth(calendarToNextMonth.get(Calendar.YEAR), calendarToNextMonth.get(Calendar.MONTH))
        }

        binding.goToPreviousMonth.setOnClickListener {
            val shownYear = binding.yearMonth.getTag(R.id.year).toString().toInt()
            val shownMonthIndex = binding.yearMonth.getTag(R.id.month_index).toString().toInt()
            val calendarToPreviousMonth = Calendar.getInstance()
            calendarToPreviousMonth.set(Calendar.YEAR, shownYear)
            calendarToPreviousMonth.set(Calendar.MONTH, shownMonthIndex)
            calendarToPreviousMonth.add(Calendar.MONTH, -1)

            val yearMonthStr = getYearMonthStr(calendarToPreviousMonth.get(Calendar.YEAR), calendarToPreviousMonth.get(Calendar.MONTH))
            binding.yearMonth.text = yearMonthStr
            binding.yearMonth.setTag(R.id.year, calendarToPreviousMonth.get(Calendar.YEAR))
            binding.yearMonth.setTag(R.id.month_index, calendarToPreviousMonth.get(Calendar.MONTH))

            sleepRecordViewModel.onChangeMonth(calendarToPreviousMonth.get(Calendar.YEAR), calendarToPreviousMonth.get(Calendar.MONTH))
        }





        return binding.root
    }

    private fun getYearMonthStr(year: Int, monthIndex: Int): String {
        val yearStr = year.toString()
        val monthStr = (monthIndex   1).toString()
        val zeroPaddingMonthStr = "00${monthStr}".substring("00${monthStr}".length - 2)


        return "${yearStr}/${zeroPaddingMonthStr}"
    }


}

fragment_sleep_record.xml

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="sleepRecordViewModel"
            type="com.example.sleeprecorder.sleeprecord.SleepRecordViewModel" />

    </data>
    <ScrollView
        android:id="@ id/sleep_record_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@ id/year_month_navigation"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:id="@ id/go_to_previous_month"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/go_to_previous_month"
                    android:textSize="22sp"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintEnd_toStartOf="@id/year_month"
                    />

                <TextView
                    android:id="@ id/year_month"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text=""
                    android:textSize="22sp"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintStart_toEndOf="@id/go_to_previous_month"
                    app:layout_constraintEnd_toStartOf="@id/go_to_next_month"/>


                <TextView
                    android:id="@ id/go_to_next_month"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/go_to_next_month"
                    android:textSize="22sp"
                    app:layout_constraintStart_toEndOf="@id/year_month"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    />
                <Button
                    android:id="@ id/add_sleep_record"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/add_sleep_record"
                    app:layout_constraintTop_toBottomOf="@id/year_month"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    />
            </androidx.constraintlayout.widget.ConstraintLayout>
        <LinearLayout
            android:id="@ id/sleep_records_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        </LinearLayout>


        </LinearLayout>
    </ScrollView>
</layout>

CodePudding user response:

Try setting WRAP_CONTENT via layoutParams as follows.

    val startSleepTextView = TextView(context)
    //startSleepTextView.width = LayoutParams.WRAP_CONTENT
    //startSleepTextView.height = LayoutParams.WRAP_CONTENT
    startSleepTextView.layoutParams = LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)

CodePudding user response:

You did not inflate the Layout it looks like from your code: If you want to set the binding layout you might want to do something like:

binding = Layout.inflate(inflator, container, false)

As I do not know what kind of layout you are using I am just substituting with a generic layout. If you use Navi view you will get different answer than FragmentManager.

CodePudding user response:

You need to call .removeAllViews() before adding any View(s) to a ViewGroup even if it is empty.

binding.sleepRecordsContainer.removeAllViews()
oneMonthSleepRecords.forEach { sleepRecord ->
  //....code
  binding.sleepRecordsContainer.addView(startSleepTextView)
}
  • Related