kotlin:error in Fragment when adding the cardstackview in a tinder like app - kotlin

I am following this tutorial about how to make a Tinder like app with Kotlin and using the third library CardStackView :
https://www.simplifiedcoding.net/tinder-like-swipe-cards-android/
However ,in my case ,shows up an error as follow:
Attempt to invoke virtual method 'void com.yuyakaido.android.cardstackview.CardStackView.setLayoutManager(androidx.recyclerview.widget.RecyclerView$LayoutManager)' on a null object reference
at com.gearsrun.stackviewapplication.UI.Home.HomePageFragment.onCreateView(HomePageFragment.kt:36)
HomeUserAdapter.kt:
package com.gearsrun.stackviewapplication.HomeUserClass
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.gearsrun.stackviewapplication.R
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.user_card.view.*
class HomeUserAdapter:RecyclerView.Adapter<HomeUserAdapter.HomeUserViewHolder>() {
private var homeUserList:List<HomeUserItem>?=null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeUserViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.user_card,parent,false)
return HomeUserViewHolder(itemView)
}
override fun onBindViewHolder(holder: HomeUserViewHolder, position: Int) {
val homeUserList = generateUser()
val currentItem = homeUserList[position]
Picasso.get().load(currentItem.user_img).into(holder.user_img)
holder.user_name.text = currentItem.user_name
holder.medal_num.text = currentItem.medal_num
holder.id_num.text = currentItem.userId
holder.user_intro.text = currentItem.user_intro
holder.user_give_num.text = currentItem.user_give_num
holder.user_receive_num.text = currentItem.user_receive_num
}
private fun generateUser(): ArrayList<HomeUserItem> {
val list = ArrayList<HomeUserItem>()
list.add(
HomeUserItem(
"https://i.pinimg.com/236x/8c/64/03/8c6403cc892231f15a6845e00d7433a9.jpg",
"Maria",
"200",
"510uu",
"I am from USA ,I am an engineer ,I hope to make the world a better place",
"500",
"100")
)
)
return list
}
override fun getItemCount(): Int {
return homeUserList!!.size
}
class HomeUserViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {
val user_img : ImageView = itemView.user_img
val user_name : TextView = itemView.user_name
val medal_num : TextView = itemView.medal_num
val id_num : TextView = itemView.id_num
val user_intro : TextView = itemView.user_intro
val user_give_num : TextView = itemView.user_give_num
val user_receive_num : TextView = itemView.user_receive_num
}
}
HomePageFragment.kt
package com.gearsrun.stackviewapplication.UI.Home
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import androidx.recyclerview.widget.DefaultItemAnimator
import com.gearsrun.stackviewapplication.HomeUserClass.HomeUserAdapter
import com.gearsrun.stackviewapplication.HomeUserClass.HomeUserItem
import com.gearsrun.stackviewapplication.R
import com.yuyakaido.android.cardstackview.CardStackLayoutManager
import com.yuyakaido.android.cardstackview.CardStackListener
import com.yuyakaido.android.cardstackview.Direction
import com.yuyakaido.android.cardstackview.SwipeableMethod
import kotlinx.android.synthetic.main.fragment_home_page.*
class HomePageFragment : Fragment(),CardStackListener {
private lateinit var layoutManager: CardStackLayoutManager
private val adapter = HomeUserAdapter()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val v = inflater.inflate(R.layout.fragment_home_page, container, false)
// v.rv_UserHome.layoutManager = LinearLayoutManager(context,LinearLayoutManager.VERTICAL,false)
layoutManager = CardStackLayoutManager(context,this).apply {
setSwipeableMethod(SwipeableMethod.AutomaticAndManual)
setOverlayInterpolator(LinearInterpolator())
}
stack_view.layoutManager = layoutManager
stack_view.adapter = adapter
stack_view.itemAnimator.apply {
if(this is DefaultItemAnimator){
supportsChangeAnimations = false
}
}
return v
}
override fun onCardDragging(direction: Direction?, ratio: Float) {
TODO("Not yet implemented")
}
override fun onCardSwiped(direction: Direction?) {
TODO("Not yet implemented")
}
override fun onCardRewound() {
TODO("Not yet implemented")
}
override fun onCardCanceled() {
TODO("Not yet implemented")
}
override fun onCardAppeared(view: View?, position: Int) {
TODO("Not yet implemented")
}
override fun onCardDisappeared(view: View?, position: Int) {
TODO("Not yet implemented")
}
}
Could you please help me take a look my code ?
Thank you so much in advance !

Move all that layoutManager and stackView stuff from onCreate to onViewCreated because during onCreate your view is not created yet and same is assured in onViewCreated.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
layoutManager = CardStackLayoutManager(context,this).apply {
setSwipeableMethod(SwipeableMethod.AutomaticAndManual)
setOverlayInterpolator(LinearInterpolator())
}
stack_view.layoutManager = layoutManager
stack_view.adapter = adapter
stack_view.itemAnimator.apply {
if(this is DefaultItemAnimator){
supportsChangeAnimations = false
}
}
}
or you can refer here

Related

adding onclicklistener to recycler view with viewbinding, kotlin

Trying to add an onclicklistener to the items in my recycler view, that will use an intent to open another activity. I've tried finding examples, but I can only find examples using Java or Kotlin examples that aren't using viewbinding.
package com.truuce.anotherrvtest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.GridLayoutManager
import com.truuce.anotherrvtest.databinding.ActivityHeroBinding
class HeroActivity : AppCompatActivity() {
var binding: ActivityHeroBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHeroBinding.inflate(layoutInflater)
setContentView(binding?.root)
val adapter = CardAdapter(HeroList.heroList)
binding?.heroRV?.adapter = adapter
binding?.heroRV?.layoutManager = GridLayoutManager(applicationContext, 3)
}
override fun onDestroy() {
super.onDestroy()
binding = null
}
}
package com.truuce.anotherrvtest
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.truuce.anotherrvtest.databinding.HeroCardBinding
class CardAdapter(val heroList: List<Hero>) : RecyclerView.Adapter<CardAdapter.MainViewHolder>() {
inner class MainViewHolder(val heroBinding: HeroCardBinding) :
RecyclerView.ViewHolder(heroBinding.root) {
fun bindHero(hero: Hero){
heroBinding.heroNameTV.text = hero.heroName
heroBinding.heroIV.setImageResource(hero.image)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {
return MainViewHolder(HeroCardBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
val hero = heroList[position]
holder.bindHero(hero)
}
override fun getItemCount() = heroList.size
}
tried adding View.OnClickListener to MainViewHolder, then implemented a member. OnClick(p0: View){}, but no idea how to get it working.
You should add a functional property for a click listener in your adapter.
The Activity can set the item click listener behavior.
class CardAdapter(
val heroList: List<Hero>,
val itemClickListener: (Hero)->Unit
) : RecyclerView.Adapter<CardAdapter.MainViewHolder>() {
inner class MainViewHolder(val heroBinding: HeroCardBinding) :
RecyclerView.ViewHolder(heroBinding.root) {
fun bindHero(hero: Hero) = with(heroBinding) {
heroNameTV.text = hero.heroName
heroIV.setImageResource(hero.image)
root.setOnClickListener { itemClickListener(hero) }
}
}
//...
}
// In Activity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHeroBinding.inflate(layoutInflater)
setContentView(binding?.root)
val adapter = CardAdapter(HeroList.heroList) { hero ->
// do something with hero item when it's clicked
}
binding?.heroRV?.adapter = adapter
binding?.heroRV?.layoutManager = GridLayoutManager(applicationContext, 3)
}

Replace baseContext in Fragment

I have a little problem with baseContext in Fragment, in a nutshell, I'm making an application with Retrofit and RecyclerView, and for practice I decided to make them in Fragment,I took this code from MainActivity and then I ran into a problem that I don't know how to replace baseContext in override fun onResponse, I just replaced it with context and it still doesn't work
import androidx.lifecycle.ViewModelProvider
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.myapplicationsadas.*
import kotlinx.android.synthetic.main.fragment_main.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class MainFragment : Fragment() {
lateinit var mService: RetrofitServices
lateinit var layoutManager: LinearLayoutManager
lateinit var adapter: MyMovieAdapter
companion object {
fun newInstance() = MainFragment()
}
private lateinit var viewModel: MainViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_main, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
mService = Common.retrofitService
recyclerMovieList.setHasFixedSize(true)
//layoutManager = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false)
layoutManager = LinearLayoutManager(context)
recyclerMovieList.layoutManager = layoutManager
getAllMovie()
}
private fun getAllMovie() {
mService.getMovieList().enqueue(object : Callback<MutableList<Movie>>{
override fun onResponse(
call: Call<MutableList<Movie>>,
response: Response<MutableList<Movie>>
) {
adapter = MyMovieAdapter(baseContext, response.body() as MutableList<Movie>)
adapter.notifyDataSetChanged()
recyclerMovieList.adapter = adapter
}
override fun onFailure(call: Call<MutableList<Movie>>, t: Throwable) {
TODO("Not yet implemented")
}
})
}
}

How can I use notification on Fragment?

I want to use notification on Fragment. And if I touch button, notification will appear.
I use many ways, and I find one way to use it. but it is not worked. only run like this
2022-06-08 15:30:10.765 28876-28876/com.ebookfrenzy.sample D/MyFragment: startMyService: Intent: Intent { cmp=com.ebookfrenzy.sample/.ui.MyService }
And below one is mainFragment.kt
package com.ebookfrenzy.sample.ui.main
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.ebookfrenzy.sample.databinding.FragmentMainBinding
import com.ebookfrenzy.sample.ui.MyService
class MainFragment : Fragment() {
private var _binding: FragmentMainBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
companion object {
fun newInstance() = MainFragment()
private const val TAG = "MyFragment"
}
private lateinit var viewModel: MainViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentMainBinding.inflate(inflater, container, false)
binding.button.setOnClickListener { startMyService()
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private fun startMyService() {
Intent(context, MyService::class.java).also {
Log.d(TAG, "startMyService: Intent: $it")
// Check Android Policy
context?.startForegroundService(it)
// Less than Android Oreo
context?.startService(it)
}
}
}
MyService
package com.ebookfrenzy.sample.ui
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import androidx.annotation.Nullable
import androidx.core.app.NotificationCompat
import com.ebookfrenzy.sample.BuildConfig
import com.ebookfrenzy.sample.R
class MyService : Service() {
companion object {
private const val TAG = "MyService"
}
private val FOREGROUND_ID: Int = 290348
private val foregroundNotificationBuilder: NotificationCompat.Builder
get() = NotificationCompat.Builder(this, applicationContext.packageName).
setSmallIcon(R.mipmap.ic_launcher_round).
setContentTitle("title").
setContentText("content text").
setPriority(NotificationCompat.PRIORITY_HIGH)
override fun onCreate() {
super.onCreate()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
startForegroundService()
return START_STICKY
}
#Nullable
override fun onBind(p0: Intent?): IBinder? {
return null
}
override fun onDestroy() {
super.onDestroy()
stopForeground(true)
}
private fun createNotificationChannel() {
val channelId = applicationContext.packageName
val channelName = BuildConfig.APPLICATION_ID
val channel = NotificationChannel(
channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT
)
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(channel)
}
private fun startForegroundService() {
val notification = foregroundNotificationBuilder.build()
// when Over android oreo, need to notification channel.
createNotificationChannel()
startForeground(FOREGROUND_ID, notification)
}
}
And other codes are not corrected after created
I want to resolve this problem. Please help me...

UninitializedPropertyAccessException in Android Studio using Kotlin

I am a beginner making use of a Roomdatabase. Mostly using it to load in and pass items between tables using simple relationships.
package com.example.allin
import android.app.AlertDialog
import android.net.Uri
import android.os.Bundle
import android.view.*
import android.widget.CheckBox
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.allin.model.Clothing
import com.example.allin.viewmodel.ClosetViewModel
import kotlinx.android.synthetic.main.fragment_clothing_tops_list.view.*
import kotlinx.android.synthetic.main.grid_clothing_item.view.*
class ClothingTopsList : Fragment() {
val args: ClothingTopsListArgs by navArgs()
/**
* Use this to get the query form Database of Tops
*/
private lateinit var mClosetViewModel: ClosetViewModel
private var adapter = ClothingTopsAdapter()
//This class should only display Clothing Tops in a RecyclerView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_clothing_tops_list, container, false)
//instantiate the recyclerView
val recyclerView = view.clothing_top_rv
//asssign the adapter
recyclerView.adapter = adapter
recyclerView.layoutManager = GridLayoutManager(requireContext(), 2)
//Assign the correct data of Tops to the adapter of the RecyclerView
mClosetViewModel = ViewModelProvider(this).get(ClosetViewModel::class.java)
mClosetViewModel.selectAllTops().observe(viewLifecycleOwner, Observer { tops ->
adapter.setData(tops)
}
)
//If Item was selected. Call navController
setHasOptionsMenu(true)
return view
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.add_outfits_menu, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(item.itemId == R.id.add_clothing_to_outfit_button){
val selectedDialog = AlertDialog.Builder(this.requireContext())
selectedDialog.setPositiveButton("Yes") { _, _ ->
**//Used Here**
val action = ClothingTopsListDirections.actionClothingTopsListToAddClothingToOutfits(args.currentOutfit,adapter.selectedItem,args.currentBottom,args.currentShoes, args.currentOuterWear)
findNavController().navigate(action)
}
selectedDialog.setNegativeButton("No") { _, _ -> }
**//Used Here**
val temp = adapter.selectedItem.type
selectedDialog.setTitle("Add $temp to the outfit?")
Toast.makeText(this.requireContext(), "Added to Outfit", Toast.LENGTH_SHORT).show()
selectedDialog.create().show()
}
return super.onOptionsItemSelected(item)
}
}
/**
* This page consists of all code for the RecyclerView of Clothing Tops for selection only to add to outfits.
*/
class ClothingTopsAdapter() : RecyclerView.Adapter<ClothingTopsAdapter.MyViewHolder>() {
private var clothingTopList = emptyList<Clothing>()
**//Created Here**
lateinit var selectedItem: Clothing
inner class MyViewHolder(item: View): RecyclerView.ViewHolder(item){
var checkBox: CheckBox = item.findViewById(R.id.clothing_cb)
}
//This inflates the EXACT SAME LAYOUT as ClothingList
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.grid_clothing_top_item, parent, false)
)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = clothingTopList[position]
holder.itemView.gl_clothing_type.text = currentItem.type
holder.itemView.gl_clothing_item_photo.setImageURI( Uri.parse(currentItem.image))
holder.itemView.grid_item.setOnClickListener {
if (!holder.itemView.clothing_cb.isChecked){
**//Used Here**
selectedItem = currentItem
holder.itemView.clothing_cb.isChecked = true
}else {
holder.itemView.clothing_cb.isChecked = false
}
}
}
override fun getItemCount(): Int {
return clothingTopList.size
}
fun setData(clothing: List<Clothing>) {
this.clothingTopList = clothing
notifyDataSetChanged()
}
}
For some reason it isn't properly adding the selected item from the recyclerView adapter to the selectedItem variable.
Would appreciate any insight into why this is happening all of a sudden.
It turned out that the error occurred because I was tapping the checkbox itself and not just the card.

Kotlin intent onclick from recyclerview. Error on holder.title.context

I am trying to get my recyclerview cards to go back to the Main Activity with some passed values once they are clicked. I have tried following this answer to get a setOnClickListener on the items in my recyclerview but am still receiving errors.
package com.example.colorpicker2finalattempt
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.recycler_recall_list.view.*
class ColorAdapter(private val colorList: List<Color>): RecyclerView.Adapter<ColorAdapter.ColorViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ColorViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.recycler_recall_list, parent, false)
return ColorViewHolder(itemView)
}
override fun onBindViewHolder(holder: ColorViewHolder, position: Int) {
val currentItem = colorList[position]
holder.previewView.text = currentItem.colorPreview
holder.nameView.text = currentItem.colorName
holder.redView.text = currentItem.redValue.toString()
holder.greenView.text = currentItem.greenValue.toString()
holder.blueView.text = currentItem.blueValue.toString()
holder.itemView.setOnClickListener {
val context = holder.title.context
val intent: Intent = Intent(context, MainActivity::class.java)
intent.putExtra("testingRItem", currentItem.redValue.toString())
intent.putExtra("testingGItem", currentItem.greenValue.toString())
intent.putExtra("testingBItem", currentItem.blueValue.toString())
context.startActivity(intent)
}
}
override fun getItemCount(): Int {
return colorList.size
}
class ColorViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val previewView: TextView = itemView.tv_colorpreview
val nameView: TextView = itemView.tv_colorname
val redView: TextView = itemView.tv_redvalue
val greenView: TextView = itemView.tv_greenvalue
val blueView: TextView = itemView.tv_bluevalue
}
}
I am receiving an unresolved reference for title, how can I resolve this?
Define title in ColorViewHolder
class ColorViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val title: TextView = itemView.tv_ title// your textview id
}