class RecyclerViewAdapter(
private val listener: Listener, private val context: Context
) : ListAdapter<ItemsList, RecyclerViewAdapter.ItemHolder>(AsyncDifferConfig.Builder(ItemComparator()).build()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemHolder {
return ItemHolder.create(parent)
}
override fun onBindViewHolder(holder: ItemHolder, position: Int) {
if (position != 0) {
val previousItem = getItem(position - 1)
holder.setData(getItem(position), listener, context, position, previousItem)
}
else {
holder.setData(getItem(position), listener, context, position, null)
}
}
fun onSwipedRc(position: Int) {
val item = getItem(position)
Log.d("MyLog", "Deleted item was $item")
listener.deleteItem(item!!, position)
}
class ItemHolder(view: View) : ViewHolder(view) {
private val binding = ListItemBinding.bind(view)
private var isAnim = false
fun setData(note: ItemsList, listener: Listener, context: Context,
position: Int, previousItem: ItemsList?) = with(binding) {
val name = note.categoryName!!
val nameResID = R.string::class.java.getField(name).getInt(null)
tvCategoryTitle.setText(nameResID)
Glide.with(context).load(R.drawable::class.java.getField(formatIcPath(name)).getInt(null))
.error(R.drawable.ic_others)
.placeholder(R.drawable.ic_others).into(categoryIv)
tvPurchaseTitle.text = note.purchaseName
tvDescription.text = note.description
if (tvDescription.text.isNotEmpty()) {
ivArrow.visibility = View.VISIBLE
}
tvAmount.text = formatTrim(String.format("%.2f", note.amount))
//Make date string and set day of week
val date = note.displayed_date
if (date != null) {
if (position == 0 || date != previousItem?.displayed_date) {
tvDay.setText(getDayOfWeek(date))
tvDate.text = date.substring(0, 2)
binding.tvDate.visibility = View.VISIBLE
binding.tvDay.visibility = View.VISIBLE
} else {
binding.tvDate.visibility = View.GONE
binding.tvDay.visibility = View.GONE
}
} else {
Log.d("MyLog", "Date is null")
binding.tvDate.visibility = View.GONE
binding.tvDay.visibility = View.GONE
}
if (!note.description.isNullOrEmpty()) {
itemView.setOnClickListener {
Log.d("MyLog", "Clicked on item")
if (isAnim) {
return@setOnClickListener
}
if (BottomList.visibility == View.GONE && tvDescription.text.isNotEmpty()) {
Log.d("MyLog", "VISIBLE description")
val expItem = Item
val expHeight = BottomList
expandView(expItem, expHeight, context)
val animRotation = RotateAnimation(
0f, 180f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
)
animRotation.duration = 500
animRotation.fillAfter = true
ivArrow.startAnimation(animRotation)
} else if (BottomList.visibility == View.VISIBLE) {
Log.d("MyLog", "GONE description")
val collItem = Item
val collHeight = BottomList
collHeight.visibility = View.GONE
collapseView(collItem, collHeight)
val animRotation = RotateAnimation(
180f, 0f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
)
animRotation.duration = 250
animRotation.fillAfter = true
ivArrow.startAnimation(animRotation)
}
}
}
itemView.setOnLongClickListener {
listener.onLongClickItem(note, itemView)
true
}
}
private fun expandView(expItem: View, expHeight: View, context: Context) {
isAnim = true
val initHeight = expItem.height
expHeight.measure(
View.MeasureSpec.makeMeasureSpec(expItem.width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
val targetHeight = initHeight + expHeight.measuredHeight
val animator = ValueAnimator.ofInt(initHeight, targetHeight)
animator.addUpdateListener { animation ->
val value = animation.animatedValue as Int
val layoutParams = expItem.layoutParams
layoutParams.height = value
expItem.layoutParams = layoutParams
}
animator.duration = 200
animator.start()
animator.addListener(object: AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
isAnim = false
val animFadeIn = AnimationUtils.loadAnimation(context, R.anim.fade_in)
expHeight.startAnimation(animFadeIn)
expHeight.visibility = View.VISIBLE
}
})
}
private fun collapseView(collItem: View, collHeight: View) {
isAnim = true
val initHeight = collItem.height
collHeight.measure(
View.MeasureSpec.makeMeasureSpec(collItem.width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
val targetHeight = initHeight - collHeight.measuredHeight
val animator = ValueAnimator.ofInt(initHeight, targetHeight)
animator.addUpdateListener { animation ->
val value = animation.animatedValue as Int
val layoutParams = collItem.layoutParams
layoutParams.height = value
collItem.layoutParams = layoutParams
}
animator.duration = 200
animator.start()
animator.addListener(object: AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
isAnim = false
}
})
}
private fun getDayOfWeek(date: String): Int {
val calendar = Calendar.getInstance()
calendar.set(Calendar.YEAR, date.substring(7, 10).toInt())
calendar.set(Calendar.MONTH, date.substring(4, 5).toInt())
calendar.set(Calendar.DAY_OF_MONTH, date.substring(0, 2).toInt())
val numDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK)
val daysOfWeek = arrayListOf(
"day1",
"day2",
"day3",
"day4",
"day5",
"day6",
"day7"
)
val dayResID = R.string::class.java.getField(daysOfWeek[numDayOfWeek - 1])
.getInt(null)
return dayResID
}
private fun formatTrim(numString: String): String {
val index = numString.indexOf(',')
val sumTrim: String
if (index > 4) {
sumTrim = numString.substring(0, 4) + ".." + numString.substring(index)
Log.d("MyLog", "index = $index; sum = $numString; sum trim = $sumTrim")
} else {
sumTrim = numString
}
return sumTrim
}
private fun formatIcPath(name: String): String {
val index = name.indexOf('_')
val nameCategory = name.substring(0, index).lowercase()
return "ic_$nameCategory"
}
companion object {
fun create(parent: ViewGroup): ItemHolder {
return ItemHolder(
LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
)
}
}
}
class ItemComparator : DiffUtil.ItemCallback<ItemsList>() {
override fun areItemsTheSame(oldItem: ItemsList, newItem: ItemsList): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: ItemsList, newItem: ItemsList): Boolean {
return oldItem == newItem
}
}
interface Listener {
fun deleteItem(note: ItemsList, pos: Int)
fun onLongClickItem(note: ItemsList, view: View)
}
}
adapter.transactions = it.subList(0, 1)
adapter.transactions = it
- лаг при открытии фрагмента полностью исчез и все стало работать настолько плавно, на сколько должно и на сколько я бы хотел.private suspend fun observer(month: String, currentMonth: String) {
Log.d("MyLog", "Observer - HistoryFrag")
mainViewModel.getMonthNotes(month).observe(viewLifecycleOwner) {
if (it == null && month == currentMonth) {
Log.d("MyLog", "List is empty")
binding.rcViewHistory.visibility = View.GONE
binding.EmptyView.emptyView.visibility = View.VISIBLE
val openAnim = AnimationUtils.loadAnimation(context, R.anim.enter_empty_view)
binding.EmptyView.emptyView.startAnimation(openAnim)
} else {
binding.rcViewHistory.visibility = View.VISIBLE
binding.EmptyView.emptyView.visibility = View.GONE
Log.d("MyLog", "Submitting list...")
Log.d("MyLog", "$it")
adapter.transactions = it
//adapter.submitList(it)
}
}
}
private suspend fun observer(month: String, currentMonth: String) {
Log.d("MyLog", "Observer - HistoryFrag")
mainViewModel.getMonthNotes(month).collect {
if (it == null && month == currentMonth) {
Log.d("MyLog", "List is empty")
binding.rcViewHistory.visibility = View.GONE
binding.EmptyView.emptyView.visibility = View.VISIBLE
val openAnim = AnimationUtils.loadAnimation(context, R.anim.enter_empty_view)
binding.EmptyView.emptyView.startAnimation(openAnim)
} else {
binding.rcViewHistory.visibility = View.VISIBLE
binding.EmptyView.emptyView.visibility = View.GONE
Log.d("MyLog", "Submitting list...")
Log.d("MyLog", "$it")
adapter.transactions = it
//adapter.submitList(it)
}
}
}
fun getMonthNotes(month: String) : LiveData<List<ItemsList>> {
return dao.getMonthNotes(month).distinctUntilChanged()
}
@Query ("SELECT * FROM List_of_Items WHERE assignable_date LIKE :month ORDER BY id DESC")
fun getMonthNotes(month: String): LiveData<List<ItemsList>>
private fun setLang(context: Context = applicationContext) {
val lang = defPreferences.getString("key_language", "en")
val locale = Locale(lang)
Locale.setDefault(locale)
val resources = context.resources
val configuration = Configuration(resources.configuration)
configuration.setLocale(locale)
val displayMetrics = resources.displayMetrics
resources.updateConfiguration(configuration, displayMetrics)
currentLang = lang.toString()
recreate()
}
Возможно все-таки нужно загружать данные в адаптер из корутины, только я использовал неправильный подход?
Сколько ищу информации в интернете, никаких примеров для моего случая не нахожу, весь код написан по мануалам, и RcView самый простой написал для теста - все равно подлагивает при открытии...
Не понимаю в чем дело, ссылаюсь на то, что все же делаю сам что-то где-то не то.