Error : Type mismatch: inferred type is FirstFragment but Context was expected - kotlin

I'm tring to build an app can dial ussd code on my mobile so,
i have 2 errors in my code on kotlin, how can i solve my problem?
First Error: (Type mismatch: inferred type is FirstFragment but Context was expected)
and
Second Error: (Type mismatch: inferred type is FirstFragment but Activity was expected)
Here is my complete code
package gaur.himanshu.august.tablayout.fragments
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.app.ActivityCompat
import gaur.himanshu.august.tablayout.MainActivity
import gaur.himanshu.august.tablayout.R
import kotlinx.android.synthetic.main.fragment_first.*
class FirstFragment : Fragment() {
val REQUEST_PHONE_CALL = 1
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
button.setOnClickListener {
Toast.makeText(
context,
"You Clicked the Button",
Toast.LENGTH_SHORT
).show()
if(ActivityCompat.checkSelfPermission(this, android.Manifest.permission.CALL_PHONE)
!=PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
arrayOf(android.Manifest.permission.CALL_PHONE),
REQUEST_PHONE_CALL
)
}
else {
startCall()
}
} // END button
} // override fun onViewCreated
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if(requestCode == REQUEST_PHONE_CALL) {
startCall()
}
//super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
private fun startCall() {
if(zaad_Merchant_SLSH.text.isNotEmpty() && merchant.text.isNotEmpty()) {
var zaadFieldINT = zaad_Merchant_SLSH.text.toString().toInt()
var phoneNumber = merchant.text.toString().toInt()
if(zaadFieldINT < 500) {
Toast.makeText(
context,
"The Value is Less than 500",
Toast.LENGTH_SHORT
).show()
}
else {
val merchantNum = "*223*$phoneNumber*$zaadFieldINT%23"
val callIntent = Intent(Intent.ACTION_CALL)
callIntent.data = Uri.parse("tel:" + merchantNum)
startActivity(callIntent)
}
}
if(zaad_Merchant_SLSH.text.isEmpty() && merchant.text.isEmpty()) {
Toast.makeText(
context,
"Labada Khaanadood way madhan yihiin",
Toast.LENGTH_SHORT
).show()
}
else if(merchant.text.isEmpty()) {
//editText.text = "Labada Khanadood way madhan yihiin"
Toast.makeText(
context,
"Khaanada Telephone Num way madhantahay",
Toast.LENGTH_SHORT
).show()
}
else if(zaad_Merchant_SLSH.text.isEmpty()) {
//editText.text = "Labada Khanadood way madhan yihiin"
Toast.makeText(
context,
"Khaanada Lacagta way madhantahay",
Toast.LENGTH_SHORT
).show()
}
} // END startcall()
}

The first argument to ActivityCompat.requestPermissions() must be a Context. If you were writing this code inside an Activity (which is a subclass of Context), then passing this would work just fine. But since you're in a Fragment (which is not a subclass of Context), you can't pass this.
Try passing view.context instead. Or use requireActivity() in any spot where an Activity (and not just a Context) is needed.

Related

Kotlin: lateinit var needs to be initialized

I'm struggling with both a dilemma and an issue here. The dilemma is that I want to keep the ManagerUsers screen simple, but Google is pushing fragments. I can see a use for fragments for this screen later on, but for now, it seems like overkill. Should I use them anyway?
Second, if I do avoid fragments for now, I am struggling to finish setting up the ClickListener to simply change the name of the user in the ListView. Kotlin seems to have at least 6 different methods for doing most things, making it confusing to figure this out. Google's tutorials force you to use fragments, and others' tutorials don't really cover what I'm trying to do. When I navigate to the Manage Users activity, the app crashes. LogCat shows that userSelect needs to be initialized. I have no idea how to do that.
UserListAdapter.kt
package com.neillbarrett.debitsandcredits
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.neillbarrett.debitsandcredits.database.UsersTable
import com.neillbarrett.debitsandcredits.databinding.ActivityManageUsersBinding
class UserListAdapter(private val userSelect: (UsersTable?) -> Unit) :
ListAdapter<UsersTable, UserListAdapter.UserViewHolder>(UsersComparator()) {
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val current = getItem(position)
holder.bind(current, userSelect)
}
class UserViewHolder(private val binding: ActivityManageUsersBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(usersTable: UsersTable?, userSelect: (UsersTable?) -> Unit) {
binding.root.setOnClickListener( View.OnClickListener {
userSelect(usersTable)
binding.etEditName.setText(R.layout.activity_list_of_users.toString())
})
}
companion object {
fun create(parent: ViewGroup) : UserViewHolder {
val view: View = LayoutInflater.from(parent.context)
.inflate(R.layout.activity_manage_users, parent, false)
return UserViewHolder(ActivityManageUsersBinding.bind(view))
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.activity_manage_users, parent, false)
return UserViewHolder.create(parent)
}
class UsersComparator : DiffUtil.ItemCallback<UsersTable>() {
override fun areItemsTheSame(oldItem: UsersTable, newItem: UsersTable): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: UsersTable, newItem: UsersTable): Boolean {
return oldItem.userName == newItem.userName
}
}
}
ManageUsers.kt
package com.neillbarrett.debitsandcredits
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.TextUtils
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.activity.viewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.neillbarrett.debitsandcredits.database.CreditsAndDebitsApp
import com.neillbarrett.debitsandcredits.database.UsersTable
import com.neillbarrett.debitsandcredits.databinding.ActivityManageUsersBinding
class ManageUsers : AppCompatActivity() {
lateinit var binding: ActivityManageUsersBinding
lateinit var recyclerView: RecyclerView
lateinit var editTextAddUser: EditText
lateinit var editTextChangeUser: EditText
lateinit var newUser: String
lateinit var userSelect: ((UsersTable?) -> Unit)
var position: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityManageUsersBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
//setContentView(R.layout.activity_manage_users)
val userViewModel: UserViewModel by viewModels {
UserViewModelFactory((application as CreditsAndDebitsApp).repository)
}
recyclerView = findViewById(R.id.rec_view_userList)
editTextAddUser = findViewById(R.id.et_UserName)
editTextChangeUser = findViewById(R.id.et_Edit_Name)
val adapter = UserListAdapter(userSelect)
binding.recViewUserList.adapter = adapter
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)
userViewModel.allUsers.observe(this, Observer() {user ->
user?.let { adapter.submitList(it) }
})
val btnAddUser = findViewById<Button>(R.id.btn_AddUser)
btnAddUser.setOnClickListener {
if (TextUtils.isEmpty(editTextAddUser.text)) {
Toast.makeText(this, "User name cannot be empty", Toast.LENGTH_SHORT).show()
} else {
newUser = editTextAddUser.text.toString()
userViewModel.insertUser(UsersTable(0, newUser))
}
}
val btnChangeUser = findViewById<Button>(R.id.btn_ChangeUserName)
btnChangeUser.setOnClickListener {
if (recyclerView.getChildAdapterPosition(it) == -1) {
Toast.makeText(this, "Select a name.", Toast.LENGTH_SHORT).show()
} else {
if (editTextChangeUser.text.toString() == recyclerView.adapter.toString()) {
Toast.makeText(this, "Name has not been changed.", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this, "Name would have been changed.", Toast.LENGTH_SHORT).show()
/*val rvItemRecId: Long
rvItemRecId = adapter.getItemId(position.toInt())
userViewModel.updateUser(UsersTable(rvItemRecId.toInt(), adapter.toString()))*/
}
}
}
}
}
UserViewModel.kt
package com.neillbarrett.debitsandcredits
import androidx.lifecycle.*
import com.neillbarrett.debitsandcredits.database.UsersTable
import kotlinx.coroutines.launch
import java.lang.IllegalArgumentException
class UserViewModel(private val repository: UserRepository) : ViewModel() {
val allUsers: LiveData<List<UsersTable>> = repository.allUsers.asLiveData()
fun insertUser(user: UsersTable) = viewModelScope.launch {
repository.insertUser(user)
}
fun updateUser(user: UsersTable) = viewModelScope.launch {
repository.updateUser(user)
}
fun deleteUser(user: UsersTable) = viewModelScope.launch {
repository.deleteUser(user)
}
}
class UserViewModelFactory(private val repository: UserRepository) : ViewModelProvider.Factory{
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(UserViewModel::class.java)) {
#Suppress("UNCHECKED_CAST")
return UserViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
If you check your ManageUsers activity implementation
lateinit var userSelect: ((UsersTable?) -> Unit)
userSelect is lateinit and it must be initialised before you pass the reference to UserListAdapter adapter. Something like this
userSelect = {
// do something
}
before passing to adapter, or
val userSelect: ((UsersTable?) -> Unit) = {
}
at the time of declaration.

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.

PreferenceDialog in PreferenceActivity - Target fragment must implement TargetFragment interface

I'm trying to implement a DialogPreference in a Preference activity. I achieved it but it seems setTargetFragment is marked as deprecated.
Here is my old code:
override fun onDisplayPreferenceDialog(preference: Preference?) {
val clearStatsDialog = preference as? DialogPreferenceClearStats
if (clearStatsDialog != null) {
val dialogFragment = DialogPrefCompat.newInstance(clearStatsDialog.key)
dialogFragment.setTargetFragment(this, 0)
dialogFragment.positiveResult = {
Toast.makeText(activity, "yes", Toast.LENGTH_LONG).show()
}
dialogFragment.show(this.parentFragmentManager, null)
} else {
super.onDisplayPreferenceDialog(preference)
}
}
I wanted to replace it with setFragmentResultListener but I'm always getting "Target fragment must implement TargetFragment interface" exception.
Can someone help me?
Here is the complete code:
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.AttributeSet
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.DialogPreference
import androidx.preference.Preference
import androidx.preference.PreferenceDialogFragmentCompat
import androidx.preference.PreferenceFragmentCompat
import com.workout.intervaltimer.R
import com.workout.intervaltimer.util.WorkoutTimerUtil
class DialogPreferenceClearStats(context: Context, attrs: AttributeSet?) : DialogPreference(context, attrs), DialogPreference.TargetFragment {
override fun <T : Preference?> findPreference(key: CharSequence): T? {
TODO("Not yet implemented")
}
}
class DialogPrefCompat : PreferenceDialogFragmentCompat() {
lateinit var positiveResult: ()->Unit
override fun onDialogClosed(positiveResult: Boolean) {
if (positiveResult) {
positiveResult()
}
}
companion object {
fun newInstance(key: String): DialogPrefCompat {
val fragment = DialogPrefCompat()
val bundle = Bundle(1)
bundle.putString(PreferenceDialogFragmentCompat.ARG_KEY, key)
fragment.arguments = bundle
return fragment
}
}
}
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.settings_activity)
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment())
.commit()
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
this.parentFragmentManager.setFragmentResultListener("requestKey", viewLifecycleOwner) { requestKey, bundle ->
val dialogFragment = DialogPrefCompat.newInstance("clearStatsDialog.key")
dialogFragment.positiveResult = {
Toast.makeText(activity, "yes", Toast.LENGTH_LONG).show()
}
dialogFragment.show(this.parentFragmentManager, null)
}
}
override fun onDisplayPreferenceDialog(preference: Preference?) {
val clearStatsDialog = preference as? DialogPreferenceClearStats
if (clearStatsDialog != null) {
this.parentFragmentManager.setFragmentResult("requestKey", Bundle())
}
}
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
//It should be possible to launchs activities and websites from xml intent but I didn't achieve it.
when (preference!!.key) {
getString(R.string.force_dark_theme) -> {
WorkoutTimerUtil.setDayNightThemeForApp(requireActivity().applicationContext)
}
getString(R.string.third_party_software) -> {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(WEB_THIRD_PARTY_SOFTWARE)
startActivity(intent)
}
getString(R.string.terms_conditions) -> {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(WEB_TERMS)
startActivity(intent)
}
getString(R.string.privacy_policy) -> {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(WEB_PRIVACY_POLICY)
startActivity(intent)
}
}
return super.onPreferenceTreeClick(preference)
}
}
companion object {
const val WEB_THIRD_PARTY_SOFTWARE = "https://sites.google.com/view/that-third-party-software"
const val WEB_TERMS = "https://sites.google.com/view/that-terms-conditions"
const val WEB_PRIVACY_POLICY = "https://sites.google.com/view/that-privacy-policy"
}
}
Thanks in advance.
Doesn't look too promising: https://android-review.googlesource.com/c/platform/frameworks/support/+/1843122/8/preference/preference/src/main/java/androidx/preference/PreferenceDialogFragmentCompat.java just added #SuppressWarnings("deprecation") over the relevant code. I think that until PreferenceDialogFragmentCompat is switched over to the new API we're stuck calling setTargetFragment :(
I think the such behavour is related to the next Android bug:
https://issuetracker.google.com/issues/181793702
It still not fixed for Preferences lib 1.2.0 (Nov 1, 2022).
setTargetFragment() must be called even if lint says it is deprecated.

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

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