Retaining expandable recyclerview's layout while retrieving and updating data from API - android

I currently have a fully functioning expandable RecyclerView (with two distinct views: one for the header and the other for the contents of each header). The contents of each card under a header is retrieved from an API call to my back end.
Today, I managed to implement swipe to refresh functionality but the issue is that when I do the refresh, the groups all collapse. From a UI/UX perspective, this isn't very appealing and adds extra steps for the user. As such, what I'm looking for is a way to perform the swipe to refresh without causing the groups to collapse (i.e. the contents of the card get updated but the cards remain at the same position as when the refresh is called). I've looked at using onSaveInstanceState and onRestoreInstanceState as detailed in this answer here and here but to no avail.
My code for the adapter is as follows:
class BusStopsServicesArrivalRVAdapter :
RecyclerView.Adapter<RecyclerView.ViewHolder>(), BusStopNoSectionHeaderViewHolder.HeaderViewHolderCallback {
private val SERVICE_TYPE = 1
private val STOP_TYPE = 2
private var busStopServiceList: ArrayList<BusStopService>? = null
private var busStopList: ArrayList<String>? = null
private var busArrivalViewTypes: SparseArray<BusArrivalViewType>? = null
private var headerExpandTracker: SparseIntArray? = null
lateinit var context: Context
var nineOneCount = 0
var threeOneCount = 0
var threeNineCount = 0
var fiveNineCount = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view: View
when (viewType) {
SERVICE_TYPE -> {
view = LayoutInflater.from(parent.context)
.inflate(R.layout.card_bus_stop_service, parent, false)
return BusStopServiceHolder(view)
}
STOP_TYPE -> {
view = LayoutInflater.from(parent.context)
.inflate(R.layout.card_bus_stop_section, parent, false)
return BusStopNoSectionHeaderViewHolder(view, this)
}
else -> {
view = LayoutInflater.from(parent.context)
.inflate(R.layout.card_bus_stop_service, parent, false)
return BusStopServiceHolder(view)
}
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val itemViewType = getItemViewType(position)
val viewType = busArrivalViewTypes!!.get(position)
if (itemViewType == SERVICE_TYPE) {
bindBusStopServiceViewHolder(holder, viewType)
} else {
bindHeaderViewHolder(holder, position, viewType)
}
}
private fun bindHeaderViewHolder(holder: RecyclerView.ViewHolder, position: Int, busArrivalViewType: BusArrivalViewType) {
val dataIndex = busArrivalViewType.dataIndex
val headerViewHolder = holder as BusStopNoSectionHeaderViewHolder
when(busStopList!![dataIndex]) {
"D" -> {
headerViewHolder.busStopNoTextView.text =
context.resources.getString(R.string.bus_stop_services_description_D)
}
"C" -> {
headerViewHolder.busStopNoTextView.text =
context.resources.getString(R.string.bus_stop_services_description_C)
}
"B" -> {
headerViewHolder.busStopNoTextView.text =
context.resources.getString(R.string.bus_stop_services_description_B)
}
"A" -> {
headerViewHolder.busStopNoTextView.text =
context.resources.getString(R.string.bus_stop_services_description_A)
}
}
// headerViewHolder.busStopNoTextView.text = busStopList!![dataIndex]
if (isExpanded(position)) {
headerViewHolder.busStopNoTextView
.setCompoundDrawablesWithIntrinsicBounds(null, null, headerViewHolder.arrowUp, null)
} else {
headerViewHolder.busStopNoTextView
.setCompoundDrawablesWithIntrinsicBounds(null, null, headerViewHolder.arrowDown, null)
}
}
private fun bindBusStopServiceViewHolder(holder: RecyclerView.ViewHolder, busArrivalViewType: BusArrivalViewType) {
val dataIndex = busArrivalViewType.dataIndex
(holder as BusStopServiceHolder).bindData(busStopServiceList!![dataIndex], context)
}
override fun getItemCount(): Int {
var count = 0
if (busStopList != null && busStopServiceList != null) {
busArrivalViewTypes!!.clear()
var collapsedCount = 0
for (i in busStopList!!.indices) {
busArrivalViewTypes!!.put(count, BusArrivalViewType(i, STOP_TYPE))
count += 1
val userType = busStopList!![i]
val childCount = getChildCount(userType)
if (headerExpandTracker!!.get(i) != 0) {
// Expanded State
for (j in 0 until childCount) {
busArrivalViewTypes!!.put(count, BusArrivalViewType(count - (i + 1) + collapsedCount, SERVICE_TYPE))
count += 1
}
} else {
// Collapsed
collapsedCount += childCount
}
}
}
return count
}
override fun getItemViewType(position: Int): Int {
return if (busArrivalViewTypes!!.get(position).type === STOP_TYPE) {
STOP_TYPE
} else {
SERVICE_TYPE
}
}
private fun getChildCount(type: String): Int {
when (type) {
"D" -> return nineOneCount
"C" -> return threeOneCount
"B" -> return threeNineCount
"A" -> return fiveNineCount
else -> return 0
}
}
fun setUserListAndType(busStopServiceList: ArrayList<BusStopService>?, busStopNoList: ArrayList<String>?, c: Context) {
if (busStopServiceList != null && busStopNoList != null) {
this.busStopServiceList = busStopServiceList
this.busStopList = busStopNoList
this.context = c
busArrivalViewTypes = SparseArray<BusArrivalViewType>(busStopServiceList.size + busStopNoList.size)
headerExpandTracker = SparseIntArray(busStopNoList.size)
notifyDataSetChanged()
for (i in busStopServiceList.indices) {
when(busStopServiceList[i].busStopCode) {
"D" -> {
nineOneCount += 1
}
"C" -> {
threeOneCount += 1
}
"B" -> {
threeNineCount += 1
}
"A" -> {
fiveNineCount += 1
}
}
}
}
}
override fun onHeaderClick(position: Int) {
val viewType = busArrivalViewTypes!!.get(position)
val dataIndex = viewType.dataIndex
val userType = busStopList!![dataIndex]
val childCount = getChildCount(userType)
if (headerExpandTracker!!.get(dataIndex) == 0) {
headerExpandTracker!!.put(dataIndex, 1)
notifyItemRangeInserted(position + 1, childCount)
} else {
headerExpandTracker!!.put(dataIndex, 0)
notifyItemRangeRemoved(position + 1, childCount)
}
}
override fun isExpanded(position: Int): Boolean {
val dataIndex = busArrivalViewTypes!!.get(position).dataIndex
return headerExpandTracker!!.get(dataIndex) == 1
}
}

Related

How to deal with recyclerview showing empty row

I am building a movies app that uses "The Movie DB" API.
My app currently displaying a recyclerview filled with movies.
The problem is that some movies don't have the values I need to display the movie and it looks like this:
https://ibb.co/5FBCP5v
My question is how can I deal with it the correct way ?
Should I use recyclerview with 2 view types ?
Is there any way I can prevent the row to inflate empty data in the first place ?
This is the recyclerView Adapter:
class MainRecyclerViewAdapter(var moviesList: List<Movie>,var listener : MainRecyclerViewAdapter.MovieListener) :
RecyclerView.Adapter<MainRecyclerViewAdapter.MovieHolder>() {
inner class MovieHolder(var itemView : View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener {
fun bindViews(movie : Movie){
val imageBaseUrl = "https://image.tmdb.org/t/p/w185"
val movieTitle = itemView.findViewById<TextView>(R.id.movieTitle)
val movieYear = itemView.findViewById<TextView>(R.id.movieYear)
val movieImage = itemView.findViewById<ImageView>(R.id.movieImage)
//Rating Bar
val ratingBar = itemView.findViewById<RatingBar>(R.id.ratingBar)
val ratingInNumbers = itemView.findViewById<TextView>(R.id.ratingInNumbers)
val peopleRated = itemView.findViewById<TextView>(R.id.peopleRated)
itemView.setOnClickListener(this)
if (movie.movieName != "null" && movie.movieVoteCount != "null" && movie.movieVoteCount != "null") {
// Movie Name
movieTitle.text = movie.movieName
// Movie Year
val inputFormat = SimpleDateFormat("yyyy", Locale.getDefault())
if (movie.movieReleasedDate != null && movie.movieReleasedDate.isNotEmpty()){
val date = inputFormat.parse(movie.movieReleasedDate)
val movieYearString: String = inputFormat.format(date?.time)
movieYear.text = movieYearString
}
// Image
Glide.with(itemView.context).load(imageBaseUrl + movie.moviePoster).into(movieImage)
Log.e("ImageuRL", "URL: " + movie.moviePoster)
// Rating Bar
if (movie.movieVotesAverge != null){
val ratingDivider = movie.movieVotesAverge.toDouble() / 2
ratingBar.rating = ratingDivider.toFloat()
ratingInNumbers.text = ratingDivider.toString()
}
// Rating
if (movie.movieVoteCount != null){
movie.movieVoteCount = when {
abs(movie.movieVoteCount.toDouble() / 1000000) > 1 -> {
(movie.movieVoteCount.toDouble() / 1000000).toString().toString() + "m"
}
abs(movie.movieVoteCount.toDouble() / 1000) > 1 -> {
(movie.movieVoteCount.toDouble() / 1000).toString().toString() + "k"
}
else -> {
movie.movieVoteCount.toInt().toString()
}
}
}
val ratedPeopleString = "(${movie.movieVoteCount})"
peopleRated.text = ratedPeopleString
}
}
override fun onClick(view: View?) {
val position = adapterPosition
listener.onMovieClickedListener(moviesList[position])
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieHolder {
val rootView = LayoutInflater.from(parent.context).inflate(R.layout.recycler_view_row_change,parent,false)
return MovieHolder(rootView)
}
override fun onBindViewHolder(holder: MovieHolder, position: Int) {
holder.bindViews(moviesList[position])
}
override fun getItemCount(): Int {
return moviesList.size
}
fun changeCurrentList(newMovieList : List<Movie>) {
this.moviesList = newMovieList
notifyDataSetChanged()
}
interface MovieListener{
fun onMovieClickedListener(movie:Movie)
}
}
Thank you!
Filter your items before passing it to recycler view in your activity or your fragment like below
moviesList.filter{ movie ->
movie != null &&
!movie.movieName.isNullOrEmpty() &&
!movie.movieVoteCount.isNullOrEmpty() &&
!movie.movieVoteCount.isNullOrEmpty() &&
!movie.moviePoster.isNullOrEmpty()
}

Outofmemory while fetching messages from content provider in pagination

I'm trying to build a single fragment(inside an activity ofcourse) application, which displays all the messages like the default messages app. There is a recyclerview in a MessageFragment. MessageRecyclerViewAdapter is the adapter for the same. I think the culprit is MessageRecyclerViewAdapter. mValues will have a map of id to sms. But the keys are being removed mValues as soon as the viewholder is detached or recycled. So, I think all the references to sms are being removed when it's removed from recycler view, but the memory keeps on increasing almost linearly as I scroll down and results in OOM. What am I missing? (I'm a backend developer, learning android for context)
class MessageRecyclerViewAdapter(
private val mListener: OnListFragmentInteractionListener?,
private val recyclerView: RecyclerView,
val context: Context
) : RecyclerView.Adapter<MessageRecyclerViewAdapter.MessageViewHolder>() {
private val mOnClickListener: View.OnClickListener
private var mValues: LinkedHashMap<Int, Sms> = LinkedHashMap()
private var mPositionToIdMap: MutableMap<Int, Int> = mutableMapOf()
private var count: Int? = null
init {
mOnClickListener = View.OnClickListener { v ->
val id = v.tag as Int
// Notify the active callbacks interface (the activity, if the fragment is attached to
// one) that an item has been selected.
mListener?.onListFragmentInteraction(mValues[id])
}
}
fun setCount(count: Int) {
this.count = count
}
override fun onCreateViewHolder(parent: ViewGroup, position: Int): MessageViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.fragment_message, parent, false)
return MessageViewHolder(view, position)
}
//This will pass position to onCreateViewHolder, instead of viewtype
override fun getItemViewType(position: Int): Int = position
override fun onBindViewHolder(holderMessage: MessageViewHolder, position: Int) {
val sms: Sms? = mValues.get(mPositionToIdMap[position])
if (sms == null) {
Log.e("MRVA", "sms == null")
return
}
val addressText = String.format("%s (%s), id:%s, %s", sms.address, DateTimeUtil.format(sms.date), sms._id, position)
Log.e("addressText", addressText)
holderMessage.mAddressView.text = addressText
with(holderMessage.mView) {
tag = sms._id
setOnClickListener(mOnClickListener)
}
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
mValues = linkedMapOf()
mPositionToIdMap = linkedMapOf()
}
override fun onViewDetachedFromWindow(holder: MessageViewHolder) {
super.onViewDetachedFromWindow(holder)
remove(holder.mPosition)
}
override fun onViewRecycled(holder: MessageViewHolder) {
super.onViewRecycled(holder)
remove(holder.mPosition)
}
fun add(
sms: Sms,
id: Int,
position: Int
) {
mValues[id] = sms
mPositionToIdMap[position] = id
}
fun remove(mPosition: Int) {
mValues.remove(mPositionToIdMap[mPosition])
mPositionToIdMap.remove(mPosition)
}
override fun getItemCount(): Int = count ?: 0
fun getId(position: Int): Int? = mPositionToIdMap[position]
fun hasData(position: Int): Boolean = mPositionToIdMap.containsKey(position)
fun getBottomMostPositionWithData(): Int {
var position = 0
mPositionToIdMap.forEach { entry ->
position = entry.key
}
return position
}
fun getTopMostPositionWithData() = mPositionToIdMap.iterator().next().key
fun get(id: Int) = mValues[id]
inner class MessageViewHolder(val mView: View, position: Int) : RecyclerView.ViewHolder(mView) {
val mAddressView: TextView = mView.address
val mPosition = position
}
}
class SmsUtil {
private final val CONTENT_URI: String = "content://sms/inbox"
fun readAllMessages(
context: Context?,
epoch: Long? = null,
limit: Int? = null,
smsHandler: SmsHandler
) {
val cursor = getCursor(context, epoch, limit) ?: return
processSms(cursor, smsHandler)
}
private fun processSms(
cursor: Cursor?,
smsHandler: SmsHandler
) {
if (cursor == null)
return
try {
if (cursor.moveToFirst()) {
do {
val sms = getSms(cursor)
Log.v(ContentValues.TAG, "SMS read $sms")
smsHandler.handle(sms)
} while (cursor.moveToNext())
} else {
Log.v(ContentValues.TAG, "The user does not have any sms")
}
}catch (e: Exception) {
} catch (e: Error) {
} finally {
cursor.close()
}
}
private fun getCursor(context: Context?, epoch: Long? = null, limit: Int? = null): Cursor? {
val selection = if (epoch != null) String.format("%s > %s", Sms.COLUMN_DATE, epoch) else null
val sortOrder =
if (limit != null) String.format("%s desc limit %s ", Sms.COLUMN_DATE, limit) else null
//above will be compiled into sql . SELECT * FROM sms_restricted WHERE (type=1) AND (_id > 100) ORDER BY limit 100
return context?.contentResolver
?.query(Uri.parse(CONTENT_URI), null, selection, null, sortOrder)
}
private fun getSms(cursor: Cursor?): Sms? {
if (cursor == null)
return null
val sms = Sms()
sms._id =
cursor.getInt(cursor.getColumnIndexOrThrow(Sms.COLUMN_ID))
sms.threadId =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_THREAD_ID))
sms.address =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_ADDRESS))
sms.person =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_PERSON))
sms.date =
cursor.getLong(cursor.getColumnIndexOrThrow(Sms.COLUMN_DATE))
sms.dateSent =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_DATE_SENT))
sms.protocol =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_PROTOCOL))
sms.read =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_READ))
sms.status =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_STATUS))
sms.type =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_TYPE))
sms.replyPathPresent =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_REPLY_PATH_PRESENT))
sms.subject =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_SUBJECT))
sms.body =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_BODY))
sms.serviceCenter =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_SERVICE_CENTER))
sms.locked =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_LOCKED))
sms.errorCode =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_ERROR_CODE))
sms.seen =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_SEEN))
sms.subId =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_SUB_ID))
sms.creator =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_CREATOR))
sms.priority =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_PRIORITY))
return sms
}
fun getCount(context: Context?): Int {
val cursor = getCursor(context) ?: return 0
val count = cursor.count
cursor.close()
return count
}
fun getLatestMessages(
context: Context?,
epoch: Long? = null,
limit: Int? = null,
smsHandler: SmsHandler
) {
if (context == null)
return
val selection = if (epoch != null) String.format("%s > %s", Sms.COLUMN_DATE, epoch) else null
val sortOrder =
if (limit != null) String.format("%s asc limit %s ", Sms.COLUMN_DATE, limit) else null
val cursor = context.contentResolver
?.query(Uri.parse(CONTENT_URI), null, selection, null, sortOrder)
processSms(cursor, smsHandler)
}
fun getOldestMessages(
context: Context?,
epoch: Long? = null,
limit: Int? = null,
smsHandler: SmsHandler
) {
if (context == null)
return
val selection = if (epoch != null) String.format("%s < %s", Sms.COLUMN_DATE, epoch) else null
val sortOrder = String.format("%s desc limit %s ", Sms.COLUMN_DATE, limit)
val cursor = context.contentResolver
?.query(Uri.parse(CONTENT_URI), null, selection, null, sortOrder)
processSms(cursor, smsHandler)
}
}

ExpandedListView: how to expandGroup or get correct groupPosition with List<Class>

Before this problem i could expand groups.
Group and child collection was:
val header: MutableList<String> = ArrayList()
var productList : MutableList<String> = mutableListOf()
val body: MutableList<MutableList<String>> = mutableListOf()
After that I needed to add more data to my header and childs (productList). So i created two model classes:
data class Cell (var barcode: String = "", var name: String = "")
data class Product(
var barcode: String = "",
var id: String = "",
var name: String = "",
var time: String = "",
var date: String = "",
var weight: Int = 0
)
And changed my collections in Activity to:
var header: MutableList<Cell> = mutableListOf()
var productList : MutableList<Product> = mutableListOf()
val body: MutableList<MutableList<Product>> = mutableListOf()
My adapter is:
class ExpandableListAdapter(var context : Context, var expandableListView: ExpandableListView, var header : MutableList<Cell>, var body: MutableList<MutableList<Product>>) :
BaseExpandableListAdapter() {
override fun getGroup(groupPosition: Int): String {
return header[groupPosition].toString()
}
override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean {
return true
}
override fun hasStableIds(): Boolean {
return false
}
override fun getGroupView(
groupPosition: Int,
isExpanded: Boolean,
convertView: View?,
parent: ViewGroup?
): View? {
var convertView = convertView
if(convertView == null){
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
convertView = inflater.inflate(R.layout.layout_group, null)
}
val title = convertView?.findViewById<TextView>(R.id.textGroupCode)
title?.text = getGroup(groupPosition)
val det = header.get(groupPosition)
title?.setText(det.name.toString())
title?.setOnClickListener {
if (expandableListView.isGroupExpanded(groupPosition))
expandableListView.collapseGroup(groupPosition)
else
expandableListView.expandGroup(groupPosition)
Toast.makeText(context, getGroup(groupPosition).toString(), Toast.LENGTH_SHORT).show()
}
return convertView
}
override fun getChildrenCount(groupPosition: Int): Int {
return body[groupPosition].size
//return header.get(groupPosition).getChildList().size()
}
override fun getChild(groupPosition: Int, childPosition: Int): String {
return body[groupPosition][childPosition].toString()
//return header.get(groupPosition).get(childPosition)
}
override fun getGroupId(groupPosition: Int): Long {
return groupPosition.toLong()
}
override fun getChildView(
groupPosition: Int,
childPosition: Int,
isLastChild: Boolean,
convertView: View?,
parent: ViewGroup?
): View? {
var convertView = convertView
if(convertView == null){
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
convertView = inflater.inflate(R.layout.layout_child, null)
}
val title = convertView?.findViewById<TextView>(R.id.textChildId)
title?.text = getChild(groupPosition, childPosition)
val name = convertView?.findViewById<TextView>(R.id.textChildName)
val date = convertView?.findViewById<TextView>(R.id.textChildDate)
val time = convertView?.findViewById<TextView>(R.id.textChildTime)
val weight = convertView?.findViewById<TextView>(R.id.textChildWeight)
val det = body.get(groupPosition).get(childPosition)
title?.setText(det.id.toString())
name?.setText(det.name.toString())
date?.setText(det.date.toString())
time?.setText(det.time.toString())
weight?.setText(det.weight.toString())
title?.setOnClickListener {
Toast.makeText(context, getChild(groupPosition, childPosition), Toast.LENGTH_SHORT).show()
}
return convertView
}
override fun getChildId(groupPosition: Int, childPosition: Int): Long {
return childPosition.toLong()
}
override fun getGroupCount(): Int {
return header.size
}
}
Now when i try to expand/click on my group or child, i get class with his all field values. I dont get position of element. How to fix this? How to work with List of class and get correct position???
Please try this one, i have print group position, child position and handle expend event.
class ExpendNewListAdapter(
var mContext: Context,
var mListDataHeader: List<String>?,
var mListDataChild: HashMap<String, List<EventsItem>?>?) : BaseExpandableListAdapter() {
override fun getChild(groupPosition: Int, childPosititon: Int): Any {
return this.mListDataChild?.get(this.mListDataHeader?.get(groupPosition))!!.get(childPosititon)
}
override fun getChildId(groupPosition: Int, childPosition: Int): Long {
return childPosition.toLong()
}
override fun getChildView(groupPosition: Int, childPosition: Int,
isLastChild: Boolean, convertView: View?, parent: ViewGroup): View {
val events = getChild(groupPosition, childPosition) as EventsItem
val infalInflater = this.mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val childView = infalInflater.inflate(R.layout.list_item_expandable, null)
val txtListEventName = childView
.findViewById<View>(R.id.text_event_name) as TextView
Log.e("child Position",childPosition.toString())
return childView
}
override fun getChildrenCount(groupPosition: Int): Int {
return this.mListDataChild?.get(this.mListDataHeader?.get(groupPosition))?.size ?:0
}
override fun getGroup(groupPosition: Int): String? {
return this.mListDataHeader?.get(groupPosition)
}
override fun getGroupCount(): Int {
return this.mListDataHeader?.size?:0
}
override fun getGroupId(groupPosition: Int): Long {
return groupPosition.toLong()
}
override fun getGroupView(groupPosition: Int, isExpanded: Boolean,
convertView: View?, parent: ViewGroup): View {
val infalInflater = this.mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val headerView = infalInflater.inflate(R.layout.expend_list_layout, null)
val innerLayout = headerView
.findViewById<View>(R.id.layout_inner) as ConstraintLayout
val viewBottom = headerView
.findViewById<View>(R.id.view_botttom_parent) as View
Log.e("group Position",groupPosition.toString())
if(isExpanded ) {
innerLayout.setBackgroundColor(ContextCompat.getColor(mContext, R.color.button_green))
viewBottom.visibility = View.GONE
}
else
{
innerLayout.setBackgroundColor(ContextCompat.getColor(mContext,R.color.button_blue))
viewBottom.visibility=View.VISIBLE
}
return headerView
}
override fun hasStableIds(): Boolean {
return false
}
override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean {
return true
}
}
In my case i have set all events month wise, where group items are month and child items are all events which are getting from my response.you can change as per your requirement.
if (dataList != null && dataList.size > 0) {
text_empty.visibility = View.GONE
mListDataHeader = ArrayList()
mListDataChild = HashMap()
// Adding the header of parent.because month are common for each year then put static data
mListDataHeader?.add(getString(R.string.january))
mListDataHeader?.add(getString(R.string.feburary))
mListDataHeader?.add(getString(R.string.march))
mListDataHeader?.add(getString(R.string.april))
mListDataHeader?.add(getString(R.string.may))
mListDataHeader?.add(getString(R.string.june))
mListDataHeader?.add(getString(R.string.july))
mListDataHeader?.add(getString(R.string.august))
mListDataHeader?.add(getString(R.string.sep))
mListDataHeader?.add(getString(R.string.oct))
mListDataHeader?.add(getString(R.string.nov))
mListDataHeader?.add(getString(R.string.dec))
mIsRequestForAccess?.let {
if (!it) {
mListDataHeader?.add("") /* these blank item to create space in bottom for
scrolling the list up to request for access view*/
mListDataHeader?.add("")
}
}
/* In this List First we are check the list of event item is empty or not
* if it is empty then we add a blank item for "No Event Found".if the list is not blank then
* we check start and end date are common or not if it is comman then we create a new list and add a event in this list
* and if the date are not common then we get all dates between start and end date..and create a different events
* of those dates..(events name and title are common between start and end date so we change only start date of
* all event which are belong from those dates)..we show the child events for base on start dates.so we change only start date*/
for (item in dataList.indices) {
mListDataChild?.let {
if (dataList[item]?.events?.size == 0) {
var list: List<EventsItem>? = null
list = ArrayList()
val events = EventsItem(null, null, null, getString(R.string.not_events_found), null)
list.add(events)
it.put(mListDataHeader!!.get(item), list)
} else {
var newList: List<EventsItem>? = null
newList = ArrayList()
val events = dataList[item]?.events as List<EventsItem>?
val monthDate=dataList[item]?.date
events?.let {
for (i in it.indices) {
val event = it[i]
val startTime = event.startDate
val endTime = event.endDate
val startDate=Utils.getFormatedTimeFromUtc(startTime,getString(R.string.date_format_data))
val endDate=Utils.getFormatedTimeFromUtc(endTime,getString(R.string.date_format_data))
val colors = event.color
val description = event.description
val title = event.title
if (startDate.equals(endDate)) {
newList.add(event)
} else {
/* get all dates between start and end date*/
var startnewDate: String? = null
val mLists = Utils.getDates(startDate, endDate, activity)
val newFormate = SimpleDateFormat(getString(R.string.date_format_data), Locale.getDefault())
val format = SimpleDateFormat(getString(R.string.date_month_formats), Locale.getDefault())
var mDateStart: Date? = null
try {
mDateStart = newFormate.parse(startDate)
startnewDate = format.format(mDateStart)
} catch (e: ParseException) {
e.printStackTrace()
}
mLists.let {
for (data in it.indices) {
val dateFormat = SimpleDateFormat(getString(R.string.date_format_data), Locale.getDefault())
val datenew = format.format(it[data])
if (datenew == monthDate) {
val newData = dateFormat.format(it[data])
val newEvent = EventsItem(endDate, colors, description, title, newData)
newList.add(newEvent)
}
}
}
}
}
}
val sortedList = newList.sortedWith(compareBy({ it.startDate }))
it[mListDataHeader!!.get(item)] = sortedList as List<EventsItem>?
}
}
setData()
}
} else {
text_empty.visibility = View.VISIBLE
}

Nested recycler view's unable to show two independent lists

I have a vertical chat recycler-view i am trying to show multiple horizontal recycler-view's in which contain a "carousel" of card views. I am able to inflate the horizontal views but when i try to add two of the same kind of horizontal view as independent items in the parent view i either get the new data added to the original and then displayed twice or if i clear the old array the new data replaces the old data in the recycler-view and a second one is not added.
I am unsure if this is due to me not generating individual adapters per horizontal view or some array issue.
My adapter generation, called in the onBindViewHolder of the parent recycler-view:
fun generateAdapter(holder: ViewHolder): CarouselAdapter{
val layoutManager = LinearLayoutManager(appContext, LinearLayoutManager.HORIZONTAL, false )
holder.carouselView.layoutManager = layoutManager
val adapterCarousel = CarouselAdapter()
holder.carouselView.adapter = adapterCarousel
snapHelper.attachToRecyclerView(holder.carouselView)
holder.carouselView.addItemDecoration(ItemOffsetDecoration(12))
holder.carouselView.isNestedScrollingEnabled = false
layoutManager.isSmoothScrollbarEnabled = true
layoutManager.stackFromEnd = true
return adapterCarousel
}
Calling of data onto child recycler-view:
"rates" -> {
if (items[i].ratesData != null) {
val adapter = generateAdapter(holder)
for (j in 0 until (items[i].ratesData!!.size)) {
adapter.addCarousel(ChatNew(items[i].msgTime, null, null, null, items[i].ratesData!![j], null, null, null, null))
}
}
//ParseHelper.clearArrays()
}
Child adapter:
class CarouselAdapter : RecyclerView.Adapter<ViewHolderCarousel>() {
private val RATES = 1
private val IMG_BUTTON = 2
private val IMG_NO_BUTTON = 3
private val BLUE = 4
private val NO_IMG_BUTTON = 5
private val ERROR = 0
lateinit var type : String
var items: ArrayList<ChatNew> = ArrayList()
fun addCarousel(carousel: ChatNew){
items.add(carousel)
notifyItemInserted(itemCount)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolderCarousel {
return when(viewType) {
RATES -> RatesViewHolderNew(LayoutInflater.from(appContext).inflate(R.layout.carousel_rate, parent, false))
IMG_BUTTON -> ImgButtonViewHolder(LayoutInflater.from(appContext).inflate(R.layout.carousel_img_btn, parent, false))
IMG_NO_BUTTON -> ImgNoButtonViewHolder(LayoutInflater.from(appContext).inflate(R.layout.carousel_img_no_btn, parent, false))
NO_IMG_BUTTON-> NoImgButtonViewHolder(LayoutInflater.from(appContext).inflate(R.layout.carousel_no_img_btn, parent, false))
else -> BlueViewHolder(LayoutInflater.from(appContext).inflate(R.layout.carousel_noimg_nobtn, parent, false))
}
}
override fun getItemCount(): Int {
return items.size
}
override fun onBindViewHolder(holder: ViewHolderCarousel, i: Int) {
type = findType(holder)
when (type){
"rates" -> {
val ri = items[i]
//for (i in 0 until (ri.ratesData!!.size)){
holder.pnView.text = ri.ratesData?.pn
holder.mpView.text =ri.ratesData?.mp
holder.itView.text = ri.ratesData?.it
holder.brView.text = ri.ratesData?.br
holder.pfView.text = ri.ratesData?.pf
holder.aprcView.text = ri.ratesData?.aprc
holder.tpView.text = ri.ratesData?.tp
holder.headDivider!!.setBackgroundColor(ContextCompat.getColor(appContext!!, R.color.NWBlue))
// }
}
"carousel button" -> {
val ci = items[i]
holder.imgView.setImageResource(ci.carouselData?.img!!)
holder.number.text = ci.carouselData?.number
holder.title.text = ci.carouselData?.title
holder.content.text = ci.carouselData?.content
holder.magicString.text = ci.carouselData?.magicString
}
"img no button" -> {
val ci = items[i]
holder.imgViewNoBtn.setImageResource(ci.carouselData?.img!!)
holder.numberNoBtn.text = ci.carouselData?.number
holder.titleNoBtn.text = ci.carouselData?.title
holder.contentNoBtn.text = ci.carouselData?.content
holder.noButtonString.text = ci.carouselData?.noButtonString
}
"no img no button" -> {
val ci = items[i]
holder.imgViewNoImgNoBtn.setBackgroundColor(ContextCompat.getColor(appContext!!,R.color.NWBlue))
holder.numberNoImgNoBtn.text = ci.carouselData?.number
holder.titleNoImgNoBtn.text = ci.carouselData?.title
holder.contentNoImgNoBtn.text = ci.carouselData?.content
}
"no img button" -> {
val ci = items[i]
holder.imgViewNoImg.setBackgroundColor(ContextCompat.getColor(appContext!!,R.color.NWBlue))
holder.numberNoImg.text = ci.carouselData?.number
holder.titleNoImg.text = ci.carouselData?.title
holder.contentNoImg.text = ci.carouselData?.content
holder.magicStringNoImg.text = ci.carouselData?.magicString
}
}
}
override fun getItemViewType(i: Int): Int {
return when (items.isNotEmpty()) {
true -> {
when {
items[i].ratesData != null -> RATES
items[i].carouselData != null -> {
when (items[i].carouselData?.img != null) {
true -> {
return if (items[i].carouselData?.magicString != null) {
//has image and button
IMG_BUTTON
} else {
//has image but no button
IMG_NO_BUTTON
}
}
false -> {
return if (items[i].carouselData?.magicString != null) {
//has no image but button
NO_IMG_BUTTON
} else {
//has no image and no button
BLUE
}
}
}
}
else -> ERROR
}
}
false -> ERROR
}
}
fun findType(holder: ViewHolderCarousel): String {
return when (holder) {
is RatesViewHolderNew -> "rates"
is ImgButtonViewHolder -> "carousel button"
is ImgNoButtonViewHolder -> "img no button"
is NoImgButtonViewHolder -> "no img button"
is BlueViewHolder -> "no img no button"
else -> "error"
}
}
}
open class ViewHolderCarousel(view: View) : RecyclerView.ViewHolder(view) {
// looks at the view and finds components on that view
// carousel for rates
val headDivider: LinearLayout? = view.head_divider
val pnView = view.pn_view
val mpView = view.mp_view
val itView = view.it_view
val brView = view.br_view
val pfView = view.pf_view
val aprcView = view.aprc_view
val tpView = view.tp_view
//TODO: set up links for "r" sections
//carousel with img and button
val imgView = view.imageView_btn
val number = view.number_btn
val title = view.title_btn
val content = view.content_btn
val magicString = view.carousel_button_btn
//carousel with img but no button
val imgViewNoBtn = view.imageView_no_btn
val numberNoBtn = view.number_no_btn
val titleNoBtn = view.title_no_btn
val contentNoBtn = view.content_no_btn
val noButtonString = view.magic_string_no_btn
//carousel with no img or button
val imgViewNoImgNoBtn = view.imageView_no_img_no_btn
val numberNoImgNoBtn = view.number_no_img_no_btn
val titleNoImgNoBtn = view.title_no_img_no_btn
val contentNoImgNoBtn = view.content_no_img_no_btn
val imgViewNoImg = view.imageView_no_img
val numberNoImg = view.number_no_img
val titleNoImg = view.title_no_img
val contentNoImg = view.content_no_img
val magicStringNoImg = view.carousel_button_no_img
}
class RatesViewHolderNew(itemView: View) : ViewHolderCarousel(itemView)
class ImgButtonViewHolder(itemView: View) : ViewHolderCarousel(itemView)
class ImgNoButtonViewHolder(itemView: View) : ViewHolderCarousel(itemView)
class NoImgButtonViewHolder(itemView: View) : ViewHolderCarousel(itemView)
class BlueViewHolder(itemView: View) : ViewHolderCarousel(itemView)
Any ideas on how i could ensure that each time i add a new set of carousel data it gets added as an independent item in the parent view would be appreciated.
It turns out that you can fix this by having each addition to the parent adapter/view as an async task. Am unsure why this works but am not complaining.
doAsync {
adapter.addChatMessage(Chat(time, null, null, null, contentRates, null, null, null, null))
}

How to dispose a view holder linked to certain card in RecyclerView?

I am working on an android project in which I want to remove the item from vertical recycler view by swiping an item to right or left. As far as it comes to deleting the item, I am able to do that correctly. The issue arises after I delete the item and call notifyDataSetChanged().
Now while refreshing items, Adapter uses previous view holders to display cards. But while deleting an item I displaced some of its layouts to left and right. So when new item occupies the same view holder all the translation is preserved and
some views of the new item are thus created out of bounds of the screen(as I displaced that view holder while deleting the previous item that occupied that spot).
So my question is (solution to any one of the following will solve the issue I am facing),
Is there "free" function like c++ in Java? So that I can free that view holder.
How to make sure that recycler view doesn't reuse particular view holder?
How to reset layout of to the original state before all animations were done? So that I can just reset all translations
Thank you.
Edits:
Below are the codes for adapter and view holder if someone wants to have a look at them.
As view holder is too large to understand directly, SO here is summery for functions used in it:
init -> just set on click listener.
updateUI -> sets some more listener and set text and other fields from card.
pressDown -> is called when MotionEvent.ACTION_DOWN.
pressUP -> is called when MotionEvent.ACTION_UP.
animateViewDisappear -> listener for animation.
archive -> delete an element and tell adapter data is change.
pressMove -> sense when motion happens after clicking button.
toggleShowHideView -> change visibility of some view.
closeOpenedLayout -> Close some expanded layouts.
Adapter:
class LocalAdapter(var localCardsInfo : ArrayList<LocalModel>?,var fragment: LocalListingFragment) : RecyclerView.Adapter<LocalHolder>() {
fun refreshDataOnOrientationChange(mLocalCards : ArrayList<LocalModel>?){
if (localCardsInfo!!.size>0)
localCardsInfo!!.clear()
localCardsInfo = mLocalCards
notifyDataSetChanged()
}
override fun getItemCount(): Int {
return localCardsInfo!!.size
}
override fun onBindViewHolder(holder: LocalHolder, position: Int) {
if (localCardsInfo!=null)
holder.updateUI(position,localCardsInfo!![position])
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LocalHolder {
val card_a : View = LayoutInflater.from(parent.context).inflate(R.layout.card_local_a,parent,false)
return LocalHolder(card_a,fragment)
}
}
view holder:
class LocalHolder(itemView : View,val fragment: LocalListingFragment) : RecyclerView.ViewHolder(itemView),OpenedLayoutManagerLocal{
private val TAG = "iotcontrollerapp.#Debug"
private var _xDelta: Float = 0f
private var originalDelta : Float = 0f
private var directionOut1 = false
private var directionOut = false
private var previousX = 0f
var isFavourite : Boolean = false
var isPropertyPanelOpen : Boolean = false
val deviceName : TextView = itemView.findViewById(R.id.deviceNameLocal)
val deviceRoom : TextView = itemView.findViewById(R.id.deviceRoomLocal)
val deviceOnOff : TextView = itemView.findViewById(R.id.deviceOnOffLocal)
val showHideLayout : LinearLayout = itemView.findViewById(R.id.showHideLayoutLocal)
val showHideProperties : TextView = itemView.findViewById(R.id.showHidePropertiesLocal)
val showHideButton : ImageView = itemView.findViewById(R.id.showHideButtonLocal)
val favouriteButton : ImageButton = itemView.findViewById(R.id.imageFavouriteButtonLocal)
val moveButton : MoveableViewImageButton = itemView.findViewById(R.id.imageMoveButtonLocal)
val changeFragmentToDetail : Button = itemView.findViewById(R.id.changePropertiesLocal)
val layoutForProperties : LinearLayout = itemView.findViewById(R.id.layoutForPropertyLocal)
val baseForProperties : LinearLayout = itemView.findViewById(R.id.baseForPropertyLocal)
private var model : LocalModel? = null
init {
itemView.elevation = 0f
showHideLayout.setOnClickListener({
isPropertyPanelOpen = !isPropertyPanelOpen
if (isPropertyPanelOpen){
if (openedLayoutManagerLocal != this)
openedLayoutManagerLocal?.closeOpenedLayout()
openedLayoutManagerLocal = this
showHideProperties.text = fragment.getString(R.string.close_property_panel)
showHideButton.setImageResource(R.drawable.animated_more_button_local)
}
else{
showHideProperties.text = fragment.getString(R.string.open_property_panel)
showHideButton.setImageResource(R.drawable.animated_more_button_reverse_local)
}
val mDrawable = showHideButton.drawable
if (mDrawable is Animatable)
{
(mDrawable as Animatable).start()
}
toggleShowHideView()
})
}
fun changeFavouriteButtonState(localModel: LocalModel){
isFavourite = !isFavourite
if (isFavourite){
favouriteButton.setImageResource(R.drawable.avd_heart_fill)
val a = favouriteButton.drawable
if(a is Animatable){
a.start()
}
ALL_STATIC_CONSTANTS_AND_METHODS.saveIsFavourite(fragment.activity as Context,localModel.roomName.trim() + "$" + localModel.deviceName,true)
}
else{
favouriteButton.setImageResource(R.drawable.avd_heart_break)
val a = favouriteButton.drawable
if(a is Animatable){
a.start()
}
ALL_STATIC_CONSTANTS_AND_METHODS.saveIsFavourite(fragment.activity as Context,localModel.roomName.trim() + "$" + localModel.deviceName,false)
}
}
fun updateUI(position : Int , localModel: LocalModel){
itemView.elevateLayoutLocal.visibility = View.VISIBLE
itemView.archiveLayout.visibility = View.VISIBLE
model = localModel
originalDelta = itemView.elevateLayoutLocal.x
changeFragmentToDetail.setOnClickListener({
fragment.handlerForDetail.sendEmptyMessage(position)
})
favouriteButton.setOnClickListener({
changeFavouriteButtonState(localModel)
})
moveButton.setOnTouchListener({v: View?, event: MotionEvent? ->
if (v == null || event == null) return#setOnTouchListener true
when (event.action){
MotionEvent.ACTION_UP -> {
v.performClick()
pressUP(v,event)
}
MotionEvent.ACTION_DOWN -> {
pressDown(v,event)
}
MotionEvent.ACTION_MOVE -> {
pressMove(v,event)
}
else -> {
Log.e(TAG,"Something happened")
}
}
return#setOnTouchListener true
})
isFavourite = (ALL_STATIC_CONSTANTS_AND_METHODS.getIsFavourite(fragment.activity as Context,localModel.roomName.trim() + "$" + localModel.deviceName) ?: false)
favouriteButton.setImageResource(if (isFavourite) R.drawable.vd_trimclip_heart_full else R.drawable.vd_trimclip_heart_empty)
deviceRoom.text = localModel.roomName.split("_").dropLast(1).toTypedArray().joinToString(" ")
deviceName.text = localModel.deviceName.split("_").dropLast(1).toTypedArray().joinToString(" ")
deviceOnOff.text = if (localModel.isON) fragment.getString(R.string.device_on_off_on) else fragment.getString(R.string.device_on_off_off)
val components = localModel.componentName.split(" ")
val value = localModel.value.split(" ")
val maxValue = localModel.maxValue.split(" ")
val minValue = localModel.minValue.split(" ")
if (layoutForProperties.childCount > 0)
layoutForProperties.removeAllViews()
if (components.size == value.size && minValue.size == maxValue.size && components.size == minValue.size){
for (i in 0 until components.size){
val layout : LinearLayout = LinearLayout.inflate(fragment.activity , R.layout.card_local_b , null) as LinearLayout
layout.findViewById<TextView>(R.id.propertyLocal).text = components[i].replace("_"," ")
layout.findViewById<TextView>(R.id.valueLocal).text = value[i]
layout.findViewById<TextView>(R.id.rangeLocal).text = minValue[i] + " to " + maxValue[i]
layoutForProperties.addView(layout)
}
}
}
private fun pressDown(imageButton: View, event: MotionEvent){
fragment.mLayoutManager?.setScrollEnabled(false)
openedLayoutManagerLocal?.closeOpenedLayout()
_xDelta = itemView.elevateLayoutLocal.x - event.rawX
}
private fun pressUP(imageButton: View, event: MotionEvent){
Log.e(TAG,"itemView.elevateLayoutLocal.x :: ${(itemView.elevateLayoutLocal.width / 3.toFloat()) - itemView.elevateLayoutLocal.x}")
val status = (itemView.elevateLayoutLocal.width / 3.toFloat()) < itemView.elevateLayoutLocal.x
val status1 = (itemView.elevateLayoutLocal.width / 2.toFloat()) < itemView.elevateLayoutLocal.x
itemView.elevateLayoutLocal.animate()
.x(if ((directionOut && status) || (status1 && directionOut1)) itemView.elevateLayoutLocal.width.toFloat() else originalDelta)
.setDuration(100)
.setListener(object : Animator.AnimatorListener{
override fun onAnimationCancel(animation: Animator?) {
if ((directionOut && status) || (status1 && directionOut1)) {
itemView.elevateLayoutLocal.visibility = View.GONE
val anim = ValueAnimator.ofInt(itemView.archiveLayout.measuredHeight, 0)
anim.addUpdateListener { valueAnimator ->
val `val` = valueAnimator.animatedValue as Int
val layoutParams = itemView.archiveLayout.layoutParams
layoutParams.height = `val`
itemView.archiveLayout.layoutParams = layoutParams
}
anim.addListener(animateViewDisappear(this#LocalHolder))
anim.duration = 1000
anim.start()
}else{
fragment.mLayoutManager?.setScrollEnabled(true)
}
}
override fun onAnimationEnd(animation: Animator?) {
if ((directionOut && status) || (status1 && directionOut1)) {
itemView.elevateLayoutLocal.visibility = View.GONE
val anim = ValueAnimator.ofInt(itemView.archiveLayout.measuredHeight, 0)
anim.addUpdateListener { valueAnimator ->
val `val` = valueAnimator.animatedValue as Int
val layoutParams = itemView.archiveLayout.layoutParams
layoutParams.height = `val`
itemView.archiveLayout.layoutParams = layoutParams
}
anim.addListener(animateViewDisappear(this#LocalHolder))
anim.duration = 1000
anim.start()
}else{
fragment.mLayoutManager?.setScrollEnabled(true)
}
}
override fun onAnimationRepeat(animation: Animator?) {
}
override fun onAnimationStart(animation: Animator?) {
}
}).start()
}
class animateViewDisappear(var i : LocalHolder) :Animator.AnimatorListener {
override fun onAnimationCancel(animation: Animator?) {
i.itemView.archiveLayout.visibility = View.GONE
i.itemView.elevateLayoutLocal.visibility = View.GONE
i.itemView.elevateLayoutLocal.x = i.originalDelta
val layoutParams = i.itemView.archiveLayout.layoutParams
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
i.itemView.archiveLayout.layoutParams = layoutParams
i.archived()
}
override fun onAnimationEnd(animation: Animator?) {
i.itemView.archiveLayout.visibility = View.GONE
i.itemView.elevateLayoutLocal.visibility = View.GONE
i.itemView.elevateLayoutLocal.x = i.originalDelta
val layoutParams = i.itemView.archiveLayout.layoutParams
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
i.itemView.archiveLayout.layoutParams = layoutParams
i.archived()
}
override fun onAnimationRepeat(animation: Animator?) {
}
override fun onAnimationStart(animation: Animator?) {
}
}
private fun archived(){
fragment.mLayoutManager?.setScrollEnabled(true)
if (model != null) {
ALL_STATIC_CONSTANTS_AND_METHODS.addToArchive(fragment.activity!!, model!!.roomName, model!!.deviceName)
fragment.mAdapter?.refreshDataOnOrientationChange(LocalDataService.ourInstance.getNonArchivedItems(fragment.activity!!))
}
}
private fun pressMove(imageButton: View, event: MotionEvent){
directionOut1 = itemView.elevateLayoutLocal.x >= (previousX)
directionOut = itemView.elevateLayoutLocal.x >= (previousX + 20)
previousX = itemView.elevateLayoutLocal.x
fragment.mLayoutManager?.setScrollEnabled(false)
itemView.elevateLayoutLocal.animate()
.x(event.rawX + _xDelta)
.setDuration(0)
.start()
}
fun toggleShowHideView(){
changeFragmentToDetail.visibility = if (isPropertyPanelOpen) View.VISIBLE else View.GONE
layoutForProperties.visibility = if (isPropertyPanelOpen) View.VISIBLE else View.GONE
baseForProperties.visibility = if (isPropertyPanelOpen) View.VISIBLE else View.GONE
}
override fun closeOpenedLayout() {
if (isPropertyPanelOpen){
isPropertyPanelOpen = !isPropertyPanelOpen
showHideProperties.text = fragment.getString(R.string.open_property_panel)
showHideButton.setImageResource(R.drawable.animated_more_button_reverse_local)
val mDrawable = showHideButton.drawable
if (mDrawable is Animatable)
{
(mDrawable as Animatable).start()
}
toggleShowHideView()
}
}
companion object {
var openedLayoutManagerLocal : OpenedLayoutManagerLocal? = null
}
}

Categories

Resources