How to use the searchView widget in a Fragment (Kotlin) - kotlin

I'm trying to use the searchView widget in a fragment. I can't find a way to do it. It's easier to implement a searchView using an Activity but I have no clue how to do implement it in a fragment in Kotlin. I tried this way but doesn't seem to work ( only works in an activity). I'm a beginner in Android and would really appreciate some help here, i've been struggling for a couple of days rn.
class Homepage : Fragment() {
private var layoutManager : RecyclerView.LayoutManager? = null
private var _binding : FragmentHomepageBinding? = null
private val binding get() = _binding!!
private val shoe = DataSource.shoes
val arrayList = ArrayList<Shoe>()
val displayList = ArrayList<Shoe>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentHomepageBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val myAdapter = ShoeAdapter(displayList)
layoutManager = GridLayoutManager(this.context,2)
recyclerView.layoutManager = layoutManager
recyclerView.adapter = myAdapter
setHasOptionsMenu(true)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.main_menu,menu)
val menuItem = menu.findItem(R.id.search)
val searchView = menuItem.actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
if(newText!!.isNotEmpty()){
displayList.clear()
val search = newText.lowercase(Locale.getDefault())
arrayList.forEach {
if(it.name.lowercase(Locale.getDefault()).contains(search)){
displayList.add(it)
}
}
recyclerView.adapter!!.notifyDataSetChanged()
}
else{
displayList.clear()
displayList.addAll(arrayList)
recyclerView.adapter!!.notifyDataSetChanged()
}
return true
}
})
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return super.onOptionsItemSelected(item)
}
}```

I used it as below before and it was working properly.
class BooksFragment : Fragment(), SearchView.OnQueryTextListener {
private lateinit var binding: FragmentBooksBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentBooksBinding.inflate(inflater, container, false)
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_books, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.toolbar_menu,menu)
val item = menu.findItem(R.id.search_book)
val searchView = item.actionView as SearchView
searchView.setOnQueryTextListener(this)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onQueryTextSubmit(query: String): Boolean {
// search button submit
return true
}
override fun onQueryTextChange(newText: String): Boolean {
// search text changed
return true
}

Related

RecyclerView adapter doesnt execute any methods

I am working on a simple project. I am trying to show list of data but in adapter none of the methods are called
class PlacnikiAdapter(private val placniki: List<Placnik>) :
RecyclerView.Adapter<PlacnikiAdapter.ViewHolder>() {
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView
init {
// Define click listener for the ViewHolder's View.
textView = view.findViewById(R.id.ime)
}
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(viewGroup.context).inflate(R.layout.layout_rv_item,
viewGroup, false)
return ViewHolder(inflater)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.textView.text = placniki[position].ime
}
override fun getItemCount(): Int {
return placniki.size
}
class PlacnikiFragment : Fragment() {
private val TAG = "PlacnikiFragment"
private lateinit var binding: PlacnikiFragmentBinding
lateinit var viewModel: MainViewModel
private val retrofitService = RetrofitService.getInstance()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Defines the xml file for the fragment
return inflater.inflate(R.layout.placniki_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = PlacnikiFragmentBinding.inflate(layoutInflater)
//get viewmodel instance using MyViewModelFactory
viewModel =
ViewModelProvider(this, ViewModelFactory(Repository(retrofitService))).get(
MainViewModel::class.java
)
//set recyclerview adapter
viewModel.placnikiList.observe(viewLifecycleOwner, {
Log.d(TAG, "placnikiList: $it")
binding.recyclerview.adapter = PlacnikiAdapter(it)
})
viewModel.errorMessage.observe(viewLifecycleOwner, {
Log.d(TAG, "errorMessage: $it")
})
viewModel.getVsiPlacniki()
}
I dont know what could be causing this. I changed activity to a fragment and beforehand everything worked normally and after changing to fragment recyclerview isnt showing items and the list isnt empty either so i dont pass list of zero items
I found the solution, the problem was in data binding. I had to add below code in gradle module
buildFeatures{dataBinding = true}

How to pass data from a BottomSheetFragment to another fragment?

I have an Activity, called 'HomeActivity', where I have a bottom navigation menu and four fragments. The activity has a FloatingActionButton and when I hit this, it opens a bottomSheetFragment which contain a RecyclerView and when I hit an item from it, I want some values to send to the fragment ('HomeFragment') which is part of the 'HomeActivity'
After doing a lot of searches online, I have done the following but I am not able to get the data in the fragment.
Following is the fragment from which I want to send the data.
'HomeBottomSheetFragment.kt'
class HomeBottomSheetFragment: BottomSheetDialogFragment() {
private lateinit var binding: FragmentHomeBottomSheetBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
FirestoreClass().getCategoryList(this)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
binding = FragmentHomeBottomSheetBinding.inflate(inflater, container, false)
return binding.root
}
fun successCategoryList(categoryList: ArrayList<ProdCategories>) {
binding.rvHomeCategories.visibility = View.VISIBLE
binding.rvHomeCategories.layoutManager = GridLayoutManager(context, 4)
binding.rvHomeCategories.setHasFixedSize(true)
val categoryAdapter = CategoryListAdapter(requireContext(), categoryList)
binding.rvHomeCategories.adapter = categoryAdapter
categoryAdapter.setOnClickListener(object :CategoryListAdapter.OnClickListener{
override fun onClick(position: Int, category: ProdCategories) {
val myFragment = HomeFragment()
val bundle = Bundle()
bundle.putString("category", category.category_name)
myFragment.arguments = bundle
fragmentManager?.beginTransaction()?.replace(R.id.nav_host_fragment,HomeFragment())?.commit()
}
})
}
}
Following is the adapter of the above fragment ('HomeBottomSheetFragment.kt'), 'CategoryListAdapter.kt'.
open class CategoryListAdapter(private val context: Context, private var list: ArrayList<ProdCategories>)
: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var onClickListener: OnClickListener? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return MyViewHolder(
HomeBottomsheetCategoryListLayoutBinding.inflate(
LayoutInflater.from(
parent.context
), parent, false
)
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val model = list[position]
if (holder is MyViewHolder) {
GlideLoader(context).loadProductPicture(model.category_image, holder.binding.ivCategoryImage)
holder.binding.tvCategoryName.text=model.category_name
}
holder.itemView.setOnClickListener {
if (onClickListener != null) {
onClickListener!!.onClick(position, model)
}
}
}
override fun getItemCount(): Int {
return list.size
}
fun setOnClickListener(onClickListener: OnClickListener) {
this.onClickListener = onClickListener
}
interface OnClickListener{
fun onClick(position: Int, category: ProdCategories)
}
private class MyViewHolder(val binding: HomeBottomsheetCategoryListLayoutBinding) : RecyclerView.ViewHolder(binding.root)
}
Following is the fragment where I want to receive the data.
class HomeFragment : BaseFragment() {
private var filterCategory: String?= null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
binding = FragmentHomeBinding.inflate(inflater, container, false)
val bundle = this.arguments
if (bundle!=null) {
filterCategory = bundle.getString("category")
}
return binding.root
}
}
All I know is that I am not doing things right, please help me fix it.
In this line,
fragmentManager?.beginTransaction()?.replace(R.id.nav_host_fragment,HomeFragment())?.commit()
Replace HomeFragment() with myFragment because that's where you are attaching the bundle.
See if this solves your problem.

Recycler View and DialogFragment struggling (Kotlin)

Hello i am using a recyclerView to swipe and call for a Dialog fragment
The the idea is that when i dismiss the dialog Fragment the raw come back to the original place
but the problem is that it return, just after the dialog is opened.
So i do not how to call notifyItemChanged inside the dialogFragment, or implement the dialogFragment.setOnDismissListener because when i override i dont know how to pass to the function the adapter to call notifyItemChanged i
This is my code
class Fragmento : Fragment(), RecyclerAdapter.ClickListener {
// TODO: Rename and change types of parameters
private lateinit var adapter :RecyclerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val view =inflater.inflate(R.layout.fragment_fragmento, container,false)
initRecyclerView(view)
return view
}
private fun initRecyclerView(view: View) {
val recyclerView = view.findViewById<RecyclerView>(R.id.recyclerView)
recyclerView.layoutManager=LinearLayoutManager(activity)
adapter = RecyclerAdapter()
recyclerView.adapter=adapter
val itemSwipe=object:ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.LEFT){
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
showDialog(viewHolder as RecyclerAdapter.ViewHolder)
var dialog = DialogFragment()
dialog.show(childFragmentManager,"dialog")
adapter.notifyItemChanged(viewHolder.adapterPosition)
}
}
val swap =ItemTouchHelper(itemSwipe)
swap.attachToRecyclerView(recyclerView)
}
private fun showDialog(viewHolder: RecyclerAdapter.ViewHolder){
val builder= AlertDialog.Builder(activity)
builder.setTitle("DeleteItem")
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance() =
Fragmento().apply {
arguments = Bundle().apply {
}
}
}
}
and for the DialogFragment
class DialogFragment: DialogFragment(){
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
var rootView: View = inflater.inflate(R.layout.dialog_fragment_noticias, container, false)
return rootView
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
}
}
If I have understand the problem here is that you want to call notifyItemChanged() when your dialog is dismiss without setOnDismissListener.
If you want to do that you can simply add a callback on your DialogFragment and use it in your recyclerView.
class DialogFragment(dismiss: () -> Unit): DialogFragment(){
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
var rootView: View = inflater.inflate(R.layout.dialog_fragment_noticias, container, false)
return rootView
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
dismiss()
}
}
When you are creating the DialogFragment you can use the callback :
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
showDialog(viewHolder as RecyclerAdapter.ViewHolder)
var dialog = DialogFragment() {
//here you are notified when the dialog is dismiss
adapter.notifyItemChanged(viewHolder.adapterPosition)
}
dialog.show(childFragmentManager,"dialog")
adapter.notifyItemChanged(viewHolder.adapterPosition)
}

I am really stuck right now on moving to a different activity from a fragment

This is my Code for CallFragment.kt , when i click on btnSetupVideoCall nothing happens whereas i should be going to different activity.
class CallFragment : Fragment() {
private var param1: String? = null
private var param2: String? = null
private lateinit var binding: FragmentCallBinding
companion object {
#JvmStatic
fun newInstance(param1: String, param2: String) =
CallFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_call, container, false)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentCallBinding.inflate(layoutInflater)
binding.btnSetupVideoCall.setOnClickListener{
(activity as MainActivity?)?.let {
val intent = Intent(it, One_to_One_VC::class.java)
it.startActivity(intent)
}
}
}
}
And this is how i made fragments in mainactivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
val callFragment = CallFragment()
val chatFragment = ChatFragment()
makeCurrentFragment(callFragment)
binding.btmNvg.setOnNavigationItemSelectedListener {
when (it.itemId) {
R.id.ic_call -> makeCurrentFragment(callFragment)
R.id.ic_chat -> makeCurrentFragment(chatFragment)
else -> makeCurrentFragment(callFragment)
}
true
}
}
override fun onBackPressed() {
if(binding.btmNvg.selectedItemId == R.id.ic_call){
super.onBackPressed()
finish()
}else{
makeCurrentFragment(CallFragment())
}
}
private fun makeCurrentFragment(fragment: Fragment) =
supportFragmentManager.beginTransaction().apply {
replace(R.id.fl_wrapper , fragment)
commit()
}
}
Logcat when i click the button
The only option left for me is to make another UI since it is starting of the project only but help would be really appreciated
onCreateView should use FragmentCallBinding.inflate
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentCallBinding.inflate(inflater)
return binding.root
}
onViewCreated should not assign the binding variable
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.btnSetupVideoCall.setOnClickListener{
(activity as MainActivity?)?.let {
val intent = Intent(it, One_to_One_VC::class.java)
it.startActivity(intent)
}
}
}

How to send data as object name from Fragment to Activity

I have to send my object name "rrbQuestiontObject" to a QuizQuestionActivity
class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view=inflater.inflate(R.layout.fragment_home, container, false)
val text :TextView=view.findViewById(R.id.text_home)
text.setOnClickListener (){
val intent = Intent(getActivity(), QuizQuestionActivity::class.java)
startActivity(intent)
}
return view
}
}
In Fragment -
override fun onCreateView(inflater: LayoutInflater,container: ViewGroup,savedInstanceState: Bundle?): View? {
val view=inflater.inflate(R.layout.fragment_home, container, false)
val text :TextView=view.findViewById(R.id.text_home)
text.setOnClickListener (){
val intent = Intent(getActivity(), QuizQuestionActivity::class.java)
intent.putExtra("rrbQuestiontObject" , value)
startActivity(intent)
}
return view
}
In QuizQuestionActivity inside onCreate() -
val intent = getIntent();
val myValue = intent.getStringExtra("rrbQuestiontObject")
Log.d(TAG,"QuizQuestionActivity - "+myValue)