https://youtu.be/n8MdHNYozgs
I implemented shared element transition between fragment and activity like on the video above
val intent = Intent(context, Main2Activity::class.java)
val list = ArrayList<Pair<View, String>>()
(recyclerView.adapter as Adapter).list.forEachIndexed { index, entity ->
val itemView = recyclerView.findViewHolderForAdapterPosition(index)?.itemView
if (itemView != null) {
list.add(Pair(itemView, entity.id.toString()))
}
}
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, *list.toTypedArray())
startActivity(intent, options.toBundle())
And in the activity I display views in another recycler view.
Could you please give me an advice what I should do to avoid blinking at the end of scaling down images?
I found the solution. The thing is I used itemView as view for transition:
val itemView = recyclerView.findViewHolderForAdapterPosition(index)?.itemView
if (itemView != null) {
list.add(Pair(itemView, entity.id.toString()))
}
But need to use the following code:
val holder = MyRecyclerView.findViewHolderForAdapterPosition(index)
if (holder != null) {
with(holder as MyViewHolder) {
list.add(Pair(this.image, entity.id.toString()))
}
}
And everything works fine.
Related
Attached Layout and Code Please help me to get my Remote video in full screen
Adding View to Layout Code
private fun addVideoViews() {
if (mVideoViewsAdded || sinchServiceInterface == null) {
return //early
}
val vc = sinchServiceInterface!!.getVideoController()
if (vc != null) {
val localView = findViewById<View>(com.ayush.flow.R.id.localVideo) as RelativeLayout
val remoteview = findViewById<View>(com.ayush.flow.R.id.remoteVideo) as RelativeLayout
val lview = vc.localView
val rview=vc.remoteView
localView.addView(lview)
remoteview.addView(rview)
mVideoViewsAdded = true
localView.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
//this toggles the front camera to rear camera and vice versa
vc.toggleCaptureDevicePosition()
}
})
}
}
Thanks in Advance
Enable fullscreen mode.
See this link
https://developer.android.com/training/system-ui/immersive
I am trying to display User Profile Image and Username in a User Search view (RecycleView) by calling an adapter - code below.But the same code that works in another Adapter, and on the profile page etc gives a null pointer error and crashes? I cant seem to understand why, since it works in every other place in the app but not in this adapter? Can anybody please help me understand and resolve this issue? The code was working earlier but I then made the switch from CircularImageView to ShapeableImageView
Please note I am using a null check and the path/link to profile is not empty and same works in other palces...
AndroidRuntime: FATAL EXCEPTION: main
Process: in.latom.latom, PID: 19549
java.lang.IllegalArgumentException: Path must not be empty.
at com.squareup.picasso.Picasso.load(Picasso.java:332)
Adapter Code
class UserAdapter(mContext: Context, mUsers: List<Users>,isChatCheck: Boolean): RecyclerView.Adapter<UserAdapter.ViewHolder?>()
{
private val mContext: Context = mContext
private val mUsers:List<Users> = mUsers
private var isChatCheck: Boolean = isChatCheck
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val view: View = LayoutInflater.from(mContext).inflate(R.layout.user_search_item_layout,viewGroup,false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return mUsers.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val user: Users? = mUsers[position]
val firstname = user?.getFirstName()
val surname = user?.getSurName()
val username = "$firstname $surname"
holder.userNameText.text = username
if(user!!.getProfile() != null) {
Picasso.get().load(user.getProfile()).placeholder(R.drawable.ic_baseline_whatshot_24).fit().centerCrop().into(holder.profileImage)
}
//present tagline
if((user.getRole() != "")) {
val company = user.getCname()!!
val tag = user.getRole()!!
val companyrole = "$tag at $company"
if (tag.isNotEmpty() && company.isNotEmpty()) {
holder.tagline.text = companyrole
} else {
holder.tagline.text = tag
}
} else {
holder.tagline.visibility = View.GONE
}
//Menu on Search Fragment
holder.itemView.setOnClickListener {
val options = arrayOf<CharSequence>(
"Send Message",
"Visit Profile"
)
val builder: AlertDialog.Builder = AlertDialog.Builder(mContext)
builder.setTitle("What would you like to do?")
builder.setItems(options, DialogInterface.OnClickListener {_, which ->
if(which == 0)
{
val intent = Intent(mContext, MessageActivity::class.java)
intent.putExtra("visit_id", user!!.getUID() )
mContext.startActivity(intent)
}
if(which == 1)
{
val intent = Intent(mContext, VisitUserProfile::class.java)
intent.putExtra("visit_id", user!!.getUID() )
mContext.startActivity(intent)
}
})
builder.show()
}
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
{
var userNameText: TextView = itemView.findViewById(R.id.username)
var tagline: TextView = itemView.findViewById(R.id.tagline_status)
var profileImage: ShapeableImageView = itemView.findViewById(R.id.profile_image)
}
}
Update:
I resolved the issue by updating the below ViewHolder line for the image from ShapeAbleImageView to ImageView as defined in the layout. Bad miss on my part!
var profileImage: ImageView = itemView.findViewById(R.id.profile_image)
the issue was with incorrect widget declaration during findviewbyid, had to do a ImageView but had done a ShapeableImageView
I have listView with ringtones
I need change play_arrow image to stop image every time when music started or stoped.
When I click play on one image it become stop image and then I click play on other music item image so previous should become play_arrow and just clicked one should become stop.
The problem is on getting views by position. Everything works great on first 12 music views. And if I try to get view like this parent.getChildAt(previousListened) with previousListened > 12 it returns null.
EDIT: add adapter class
class SoundListAdapter constructor(
private var context: Context,
private val layout: Int,
private var arrayList: ArrayList<Sound>,
private val activity: FragmentActivity,
private val mediaPlayer: MediaPlayer
) : BaseAdapter() {
private var selectedPosition = -1
private var currentListened = -1
private var previousListened = -1
private var isPlaying = false
private var TAG = "SoundListAdapter"
private val mSendSoundUri: SendSoundUri = activity as SendSoundUri
interface SendSoundUri {
fun sendSoundUri(input: String?)
}
override fun getCount(): Int {
return arrayList.size
}
override fun getItem(i: Int): Any {
return ""
}
override fun getItemId(i: Int): Long {
return i.toLong()
}
private inner class ViewHolder {
internal var radioButton: RadioButton? = null
internal var txtName: TextView? = null
internal var ivPlay: ImageView? = null
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var convertView = convertView
val viewHolder: ViewHolder
if (convertView == null) {
viewHolder = ViewHolder()
val layoutInflater = context.getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
convertView = layoutInflater.inflate(layout, null)
viewHolder.txtName = convertView!!.findViewById(R.id.sound_name)
viewHolder.radioButton = convertView.findViewById(R.id.sound_radiobutton)
viewHolder.ivPlay = convertView.findViewById(R.id.ivPlay) as ImageView
convertView.tag = viewHolder
} else {
viewHolder = convertView.tag as ViewHolder
}
//check the radio button if both position and selectedPosition matches
viewHolder.radioButton?.isChecked = (position === selectedPosition)
// TODO add color to checked circle
//Set the position tag to both radio button and label
viewHolder.radioButton?.tag = position
viewHolder.ivPlay?.tag = position
viewHolder.txtName?.tag = position
viewHolder.radioButton?.setOnClickListener { v -> itemCheckChanged(v) }
viewHolder.txtName?.setOnClickListener { v -> itemCheckChanged(v) }
val music = arrayList[position]
viewHolder.txtName!!.text = music.title
// play music
viewHolder.ivPlay!!.setOnClickListener {
previousListened = currentListened
currentListened = it.tag as Int
// TODO add black square when playing
Log.d(TAG, "max items: ${parent.childCount}")
Log.d(TAG, "previousListened: $previousListened")
if (previousListened != -1 && previousListened == currentListened && mediaPlayer.isPlaying) {
mediaPlayer.stop()
} else {
mediaPlayer.reset()
mediaPlayer.setDataSource(context, Uri.parse(music.uri))
mediaPlayer.prepare()
mediaPlayer.start()
}
}
return convertView
}
private fun getSelectedSound(): Sound? {
Log.d(TAG, "sending selectedPosition: $selectedPosition")
if (selectedPosition == -1)
return null
return arrayList[selectedPosition]
}
private fun itemCheckChanged(v: View) {
selectedPosition = v.tag as Int
mSendSoundUri.sendSoundUri(getSelectedSound()?.uri)
Log.d(TAG, "selectedPosition changed to: $selectedPosition")
notifyDataSetChanged()
}
}
Is it possible to get item view of ListView that is outside of visible part in Adapter class?
Is it possible to get item view of ListView that is outside of visible part in Adapter class?
No, you can't. ViewHolder exists only for visible items.
However, in your case, you only need to set your ImageView image inside your getView function.
if (currentListened == position) {
// set here your Stop image
viewHolder.ivPlay.setImageResource(R.drawable.stop);
} else {
// set here your Play image
viewHolder.ivPlay.setImageResource(R.drawable.play);
}
Then, call notifyDataSetChanged
viewHolder.ivPlay!!.setOnClickListener {
...
...
notifyDataSetChanged();
}
notifyDataSetChange will update all visible items.
On the other hand, you don't need to save position in tag variable. You always know which item is clicked because your onClick events are set in getView function.
I'm currently using RecyclerView with MVVM databinding(well the databinding might not matter).
Anyway, what I'm trying to do is to show a certain layout view when the data in the recyclerView
is empty. It works wen I use the AdapterDataObserver onChanged(the following code). But the problem is that when I
open my app, my Empty time view shows up only for a split second(like a glitch / flicks) then show the lists normally. I'm unable to fix the
problem to not show this empty time view when a open the screen. Some sample example or code will be awesome!
I would love to hear from you !
Part of the code below
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = activity?.run {
ViewModelProviders.of(this, viewModelFactory).get(ShopViewModel::class.java)
} ?: throw Exception("Invalid Activity")
val adapter = ShopRecyclerAdapter(viewModel, mIndex))
val emptyObserver = object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
val isEmpty = adapter.itemCount == 0
val isfavImage = if (mIndex == 2) R.drawable.img_fav else R.drawable.img_none
val isNoData = if (isEmpty || adapter == null) View.VISIBLE else View.GONE
val visibility = if (isEmpty || adapter == null) View.GONE else View.VISIBLE
binding.layoutSwipeRefresh.visibility = visibility
binding.noneLayout.visibility = isNoData
binding.noneLayout.item_coupon_none_im.setImageResource(isfavImage)
}
}
adapter.registerAdapterDataObserver(emptyObserver)
emptyObserver.onChanged()
val recyclerView: RecyclerView = binding.shopRecycleView
val layoutManager = GridLayoutManager(activity, 1, RecyclerView.VERTICAL, false)
recyclerView.layoutManager = layoutManager
How do you get data for the list? Say you have a loading state that has just a loading spinner. After you get data for the list, register observer to display either empty view or populate the list
I have a listView that has a custom layout that contains a fragment. The problem I am having is when I add the fragment to the listView row I get a never ending loop that keeps going through the getView code.
I have only been doing Android coding for a couple months so any help would be great. Please let me know if there is any more of my code I need to post
This is my adapter code:
class AdapterReply(
private val context: Context,
private val ph: Phan,
private val replies: ArrayList<Reply> ) : BaseAdapter() {
override fun getCount(): Int {
return replies.size
}
override fun getItem(position: Int): Reply {
return replies[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, convertView: View?, viewGroup: ViewGroup?): View? {
val rowMain: View?
val rowHolder: ListRowHolder
val contacts = ph.contacts
val reply = replies[position]
Log.d("AdapterReply", "Binding reply: Position $position ${reply.id} Detail: ${reply.detail}")
if (convertView == null) {
val layoutInflater = LayoutInflater.from(viewGroup!!.context)
rowMain = layoutInflater.inflate(R.layout.reply_item_row, viewGroup, false)
rowHolder = ListRowHolder(rowMain)
rowMain.tag = rowHolder
Log.d("AdapterReply", "New Item")
} else {
rowMain = convertView
rowHolder = rowMain.tag as ListRowHolder
Log.d("AdapterReply", "Old item from memory")
}
rowHolder.itemDetail.text = Helpers.anonymizeContent(reply.detail, ph.anonymousMetadata, ph.isViewerMember())
rowHolder.itemLastActive.text = Helpers.getFormattedDate(reply.lastActive())
if(reply.attachments.size > 0){
val imageAttachment = reply.attachments.filter { attachment: Attachment -> attachment.type == 0 }[0]
var imageUrl = Constants.BASE_URL + imageAttachment.url
if(imageAttachment.anonymous()){
imageUrl = Constants.BASE_URL + imageAttachment.anonUrl
}
Picasso.with(rowMain!!.context).load(imageUrl).into(rowHolder.itemImage)
}
var poster: Contact? = reply.contact
if(contacts.size > 0) {
val posterList = contacts.filter { contact: Contact -> contact.id == reply.rlContactID }
if (posterList.isNotEmpty()) {
poster = posterList[0]
}
}
if(poster != null) {
if(poster.anonymizedName.isNotEmpty()) {
rowHolder.itemPoster.text = poster.anonymizedName
} else {
val posterName = "${poster.firstName} ${poster.lastName}"
rowHolder.itemPoster.text = posterName
}
//Code the causes the problem
val manager = (rowMain!!.context as AppCompatActivity).supportFragmentManager
val posterAvatarFragment =
AvatarFragment.newInstance(poster)
manager.beginTransaction()
.add(R.id.reply_avatar_fragment, posterAvatarFragment, "ReplyAvatarFragment")
.commit()
//End Code the causes the problem
}
bindReplies(rowMain, ph, reply.replies)
return rowMain
}
internal class ListRowHolder(row: View?) {
var itemDetail : TextView = row!!.reply_view_detail
var itemImage : ImageView = row!!.reply_view_image
var itemPoster : TextView = row!!.reply_view_posterName
var itemLastActive : TextView= row!!.reply_view_lastActive
var itemReplyReplies: ListView = row!!.reply_view_replyList
}
private fun bindReplies(viewRow: View?, ph: Phan, replies : ArrayList<Reply>){
if(replies.isNotEmpty()) {
val myObject = AdapterReply(context, ph, replies)
val replyListView = viewRow!!.reply_view_replyList
Log.d("AdapterReply", "Binding Replies: ${ph.encodedId} ${replies.size}")
replyListView.adapter = myObject
}
}
}
manager.beginTransaction()
.add(R.id.reply_avatar_fragment, posterAvatarFragment, "ReplyAvatarFragment")
.commit()
Man, I'm not sure do you know, what function performs adapter class in listview. Adapter class is used to fill listview by rows passed in array inside class constructor. getView method is called for every row in array, so for example, if you have an array with 10 rows, this code will fire ten times. If you do automatically change fragment to another, and during filling an old view you will change layout to a another layout with the same data, your code will make an infinity loop, because you will repeat all time the same cases. You should avoid actions, which will dynamically change layout during load him. In my sugestion, if you want to use a multiple layouts inside one adapter, there are two special methods to set layout for row, based on some conditions: getItemViewType and getViewTypeCount. In first one you can use your conditions to check, which layout should be used for row. Second one is to set number of layouts, which will be used in your adapter class. Let search some examples of usage.