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)
}