I have created a To do List app with a FAB and my code is returning three errors: Expecting ')', Expecting and Element and Unresolved Reference fab - android-studio

I have created a To do List app with a Floating Actin Button and my code is returning three errors:
Expecting ')'
Expecting an Element
Unresolved Reference fab
The code was fine until I decided to add another button to the bottom of my activity_main.xml file and needed to add a relativelayout inside a coordinator layout to do it. The new button is to allow users to change the colour of the background. Once adding this code into the MainActivity.kt file the original findViewById code for the fab no longer works and gives the above errors.
MainActivity.kt file
abstract class MainActivity : AppCompatActivity() ,UpdateAndDelete {
private lateinit var database: DatabaseReference
var toDoList: MutableList<ToDoModel>? = null
lateinit var adapter: ToDoAdapter
private var listViewItem : ListView?=null
internal abstract var screenView:View
internal abstract var clickMe:Button
internal abstract var color:Array<Int>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
intArrayOf(Color.MAGENTA, Color.YELLOW, Color.BLUE, Color.BLACK)
screenView = findViewById(R.id.rView)
clickMe = findViewById(R.id.colorButton) as Button
clickMe.setOnClickListener(object:View.OnClickListener {
override fun onClick(view: View) {
val aryLength = color.size
val random = Random
val rNum = random.nextInt(aryLength)
screenView.setBackgroundColor(color[rNum])
}
}
val fab: View = findViewById(R.id.fab)
listViewItem = findViewById<ListView>(R.id.item_listView)
database = FirebaseDatabase.getInstance().reference
fab.setOnClickListener { view ->
val alertDialog = AlertDialog.Builder(this)
val textEditText = EditText (this)
alertDialog.setMessage("Add TODO Item")
alertDialog.setTitle("Enter TO DO Item")
alertDialog.setView(textEditText)
alertDialog.setPositiveButton("Add") {dialog, i ->
val todoItemData = ToDoModel.createList()
todoItemData.itemDataText = textEditText.text.toString()
todoItemData.done = false
val newItemData=database.child("todo").push()
todoItemData.UID = newItemData.key
newItemData.setValue(todoItemData)
dialog.dismiss()
Toast.makeText(this, "item saved", Toast.LENGTH_LONG).show()
}
alertDialog.show()
}
activity_main.xml file
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
tools:context=".MainActivity">
<ListView
android:id="#+id/item_listView"
android:layout_width="match_parent"
android:layout_height="651dp"
android:background="#color/white"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:scrollbars="none" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:layout_gravity="bottom|end"
android:elevation="6dp"
app:pressedTranslationZ="12dp"
android:src="#drawable/ic_baseline_add_24" />
<RelativeLayout
android:id="#+id/rView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:gravity="bottom">
<Button
android:id="#+id/colorButton"
android:layout_width="170dp"
android:layout_height="58dp"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="22dp"
android:layout_marginBottom="11dp"
android:backgroundTint="#color/teal_200"
android:text="Change Colour"
android:textColor="#color/black" />
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Looking at this bit of your code:
clickMe.setOnClickListener(object:View.OnClickListener {
override fun onClick(view: View) {
val aryLength = color.size
val random = Random
val rNum = random.nextInt(aryLength)
screenView.setBackgroundColor(color[rNum])
}
}
val fab: View = findViewById(R.id.fab)
You are getting the first error because you are not properly closing the call to clickMe.setOnClickListener by providing a ) after the } on the second to last line. The compiler realizes this on the last line that defines fab, and so it is that line that the compiler is actually complaining about.
To fix this, add a ) to the second to last line, like this:
clickMe.setOnClickListener(object:View.OnClickListener {
override fun onClick(view: View) {
val aryLength = color.size
val random = Random
val rNum = random.nextInt(aryLength)
screenView.setBackgroundColor(color[rNum])
}
})
val fab: View = findViewById(R.id.fab)
Once you have an initial syntax error, it doesn't really matter what other errors the compiler is producing. Fix this first error and re-evaluate where you're at.
If the code you supply is supposed to be complete...that is, the entire contents of the file MainActivity.kt is provided, then you are missing a number of closing curlies (}) at the end of the code.

Related

How to drag and drop ListView rows in Android Studio using Kotlin

I’m using Android Studio with Kotlin. I’d like to be able to drag and drop items in a ListView to reorder them. I also want to swipe left to delete. This was pretty straightforward in XCode/Swift for iOS, but I’m having trouble finding examples for Android/Kotlin. I’ve seen some fairly old discussions with Java and with RecyclerView, but it would be great to be able to do it in Kotlin with ListView. I should add that the ListView does everything I need so far – I realise there is much discussion about ListView vs RecyclerView.
I’m not asking for people to solve this for me, but it would be great if you could point me to anything that might get me going.
By way of background, here is my code. It is just a ListView with numbers ‘zero’ to ‘ten’ and the selected row highlighted. I should add that I wrote this code with the help of many discussions here and on YouTube, for which I’m very grateful.
I also have a ListView with sections that needs these options, but I’ve not put the code here for that (happy to do so if required).
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="#+id/list_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_margin="16dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
listview_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/rowText"
android:layout_width="match_parent"
android:layout_height="48dp"
android:textColor="#color/black"
android:paddingLeft="0dp"
android:paddingTop="8dp"
android:paddingRight="0dp"
android:paddingBottom="8dp"
android:autoSizeTextType="uniform"
android:autoSizeMaxTextSize="40sp"
android:autoSizeMinTextSize="8sp"
android:autoSizeStepGranularity="2sp"
android:lines="1" />
</LinearLayout>
listview_selected_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/selectedRowText"
android:layout_width="match_parent"
android:layout_height="48dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:background="#color/teal_200"
android:textColor="#color/black"
android:autoSizeTextType="uniform"
android:autoSizeMaxTextSize="40sp"
android:autoSizeMinTextSize="8sp"
android:autoSizeStepGranularity="2sp"
android:lines="1" />
</LinearLayout>
ListViewAdapter.kt
package com.ijmusic.listviewrearrange
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.TextView
val TYPE_LISTVIEW_ITEM = 0
val TYPE_LISTVIEW_SELECTED_ITEM = 1
class ListViewAdapter(private val context: Context): BaseAdapter() {
private val mData: ArrayList<String> = ArrayList()
private var mIndex: ArrayList<Int> = ArrayList()
private var mSelectedItem = -1
private lateinit var textView: TextView
fun addItem(item: String, index: Int) {
mData.add(item)
mIndex.add(index)
notifyDataSetChanged()
}
fun addSelectedItem(item: String, index: Int) {
mData.add(item)
mIndex.add(index)
mSelectedItem = mData.size - 1
notifyDataSetChanged()
}
fun highlightSelection(int: Int) {
mSelectedItem = int
notifyDataSetChanged()
}
override fun getItemViewType(position: Int): Int {
return if (position == mSelectedItem) TYPE_LISTVIEW_SELECTED_ITEM
else TYPE_LISTVIEW_ITEM
}
override fun getCount(): Int {
return mData.size
}
override fun getItem(position: Int): Any {
return mData[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, view: View?, parent: ViewGroup?): View? {
var view = view
var type = getItemViewType(position)
if (position == mSelectedItem) type = TYPE_LISTVIEW_SELECTED_ITEM
when (type) {
TYPE_LISTVIEW_ITEM -> {
view = LayoutInflater.from(context).inflate(R.layout.listview_row, parent, false)
textView = view.findViewById(R.id.rowText)
}
TYPE_LISTVIEW_SELECTED_ITEM -> {
view = LayoutInflater.from(context).inflate(R.layout.listview_selected_row, parent, false)
textView = view.findViewById(R.id.selectedRowText)
}
}
textView.text = mData[position]
return view
}
}
MainActivity.kt
package com.ijmusic.listviewrearrange
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import com.ijmusic.listviewrearrange.databinding.ActivityMainBinding
val list = listOf("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten")
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var mAdapter: ListViewAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
mAdapter = ListViewAdapter(this)
setListView()
binding.listView.onItemClickListener = object: AdapterView.OnItemClickListener {
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
binding.listView.setSelection(position)
mAdapter.highlightSelection(position)
}
}
}
fun setListView() {
for ( i in 0 until list.count() ) {
if ( i == 0 )
mAdapter.addSelectedItem(list[i], i)
else
mAdapter!!.addItem(list[i], i)
}
binding.listView.adapter = mAdapter
}
}
You can look into a concept called gestures in android Kotlin. It will help.

W/RecyclerView: No adapter attached; skipping layout

I have made a basic shopping list app that utilises a recyclerview to display the list items. I am trying to add a settings screen using navigation with fragments. I am running into the issue where my recyclerview & data display when I open the app, however when I go to the settings menu then back to the main screen there's no recyclerview. Logcat shows the error "W/RecyclerView: No adapter attached; skipping layout"
MainActivity.kt
package com.example.shoppinglist
import android.app.Dialog
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.findNavController
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.floatingactionbutton.FloatingActionButton
class MainActivity : AppCompatActivity(), RVAdapter.ListItemClickInterface {
lateinit var itemsRV: RecyclerView
lateinit var addFAB: FloatingActionButton
lateinit var list: List<ListItems>
lateinit var RVAdapter: RVAdapter
lateinit var viewModel: ViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupActionBarWithNavController(findNavController(R.id.fragment_main))
itemsRV = findViewById(R.id.recyclerView)
addFAB = findViewById(R.id.idFABAdd)
list = ArrayList<ListItems>()
RVAdapter = RVAdapter(list, this)
itemsRV.layoutManager = LinearLayoutManager(this)
itemsRV.adapter = RVAdapter
val repository = Repository(Database(this))
val factory = ViewModelFactory(repository)
viewModel = ViewModelProvider(this, factory).get(ViewModel::class.java)
viewModel.getAllListItems().observe(this, Observer {
RVAdapter.list = it
RVAdapter.notifyDataSetChanged()
})
addFAB.setOnClickListener {
openDialog()
}
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.fragment_main)
return navController.navigateUp() || super.onSupportNavigateUp()
}
fun openDialog() {
val dialog = Dialog(this)
dialog.setContentView(R.layout.add_dialog)
val cancelButton = dialog.findViewById<Button>(R.id.idBtnCancel)
val addButton = dialog.findViewById<Button>(R.id.idBtnAdd)
val itemEdt = dialog.findViewById<EditText>(R.id.idEditItemName)
val itemQuantityEdt = dialog.findViewById<EditText>(R.id.idEditItemQuantity)
cancelButton.setOnClickListener {
dialog.dismiss()
}
addButton.setOnClickListener {
val itemName: String = itemEdt.text.toString()
val itemQuantity: String = itemQuantityEdt.text.toString()
if (itemName.isNotBlank() && itemQuantity.isNotBlank()) {
val items = ListItems(itemName, itemQuantity)
viewModel.insert(items)
Toast.makeText(applicationContext, "Item Added", Toast.LENGTH_SHORT).show()
RVAdapter.notifyDataSetChanged()
dialog.dismiss()
} else {
Toast.makeText(applicationContext, "Enter All Info To Add Item",
Toast.LENGTH_SHORT)
.show()
}
}
dialog.show()
}
override fun onItemClick(listItems: ListItems) {
viewModel.delete(listItems)
RVAdapter.notifyDataSetChanged()
Toast.makeText(applicationContext, "Item Deleted", Toast.LENGTH_SHORT).show()
}
}
HomeFragment.kt
package com.example.shoppinglist
import android.os.Build
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager
import kotlinx.android.synthetic.main.fragment_home.*
class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false)
}
#RequiresApi(Build.VERSION_CODES.N)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
idFABSettings.setOnClickListener {
findNavController().navigate(R.id.action_homeFragment_to_settingsFragment)
}
loadSettings()
}
#RequiresApi(Build.VERSION_CODES.N)
private fun loadSettings(){
val sp = PreferenceManager.getDefaultSharedPreferences(context)
val theme = sp.getBoolean("theme_switch",false)
}
}
SettingsFragment.kt
package com.example.shoppinglist
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="#+id/fragment_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/navigation"
/>
</RelativeLayout>
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?attr/colorPrimary"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="#layout/list_rv_item"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/idFABAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="20dp"
android:backgroundTint="?attr/colorSecondary"
android:contentDescription="Add Item Button"
android:src="#drawable/ic_add"
android:tint="#android:color/white" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/idFABSettings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="20dp"
android:backgroundTint="?attr/colorSecondary"
android:contentDescription="Add Item Button"
android:src="#drawable/ic_settings"
android:tint="#android:color/white" />
</RelativeLayout>
navigation.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/navigation"
app:startDestination="#id/homeFragment">
<fragment
android:id="#+id/settingsFragment"
android:name="com.example.shoppinglist.SettingsFragment"
android:label="Settings" >
<action
android:id="#+id/action_settingsFragment_to_homeFragment"
app:destination="#id/homeFragment" />
</fragment>
<fragment
android:id="#+id/homeFragment"
android:name="com.example.shoppinglist.HomeFragment"
android:label="Shopping List"
tools:layout="#layout/fragment_home" >
<action
android:id="#+id/action_homeFragment_to_settingsFragment"
app:destination="#id/settingsFragment" />
</fragment>
</navigation>
Not sure if any more info is required. Apologies in advance - I am new to android studio & kotlin.
You are trying to work with views that are specific to HomeFragment's layout through the MainActivity. This will not work correctly. The first time you start the activity, in onCreate you use findViewById to find the view with ID recyclerView, and it successfully finds it because at that time the view is part of the HomeFragment, which is in the layout.
However, when you change fragments, the original fragment view is detached and removed. When you return to the first fragment, Android creates a new instance of your HomeFragment and its layout. The MainActivity is still referencing the original RecyclerView from the first instance of the HomeFragment, so it will update that view that is no longer on screen and it won't touch the new view. You have actually created a memory leak where the MainActivity is preventing that first fragment's view from being destroyed.
Another issue that you haven't discovered yet possibly is that if you rotate the screen while the SettingsFragment is open, you'll crash with a NullPointerException. This is because a screen rotation will cause a new Activity to be created, so onCreate() will be called again, and when it tries to find recyclerView when the HomeFragment is not in the layout, it will fail.
It doesn't make sense to work with a Fragment's specific views from the hosting Activity. The Activity should not have to know any details about what is in a Fragment and what to do with the contents of that fragment. All your code that has to do with the RecyclerView should be in HomeFragment.

Horizontal circular RecyclerView in Kotlin?

I am using a horizontal RecyclerView and showing images using the CircleImageView widget (See image below).
I am really struggling on how to make the list of items loop around, so that if you are in the last item, you will move to the first item in the list?
I have tried quite a few similar examples but I can’t make them work as they are in Java, or are quite complex. following is my code
MainActivity.kt
class MainActivity : AppCompatActivity() {
lateinit var adapter: ConcatAdapter
lateinit var userVerticalAdapter: UsersAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupDataInRecyclerView()
}
private fun setupDataInRecyclerView() {
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
userVerticalAdapter = UsersAdapter(DataSource.getUser())
val listOfAdapters = listOf(userVerticalAdapter)
adapter = ConcatAdapter(listOfAdapters)
recyclerView.adapter = adapter
}
}
Adapter.kt
class UsersAdapter(
private val users: ArrayList<User>
) : RecyclerView.Adapter<UsersAdapter.DataViewHolder>() {
class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(user: User) {
itemView.textViewUserName.text = user.name
Glide.with(itemView.imageViewAvatar.context)
.load(user.avatar)
.into(itemView.imageViewAvatar)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
DataViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_layout, parent,false))
override fun getItemCount(): Int = users.size
override fun onBindViewHolder(holder: DataViewHolder, position: Int) =
holder.bind(users[position])
}
}
DataSource.kt
object DataSource {
fun getUser() = ArrayList<User>().apply {
add(User(1, "Chillis", R.drawable.chilli))
add(User(2, "Tomato", R.drawable.tomatoe))
add(User(3, "Sweetcorn", R.drawable.sweeetcorn))
add(User(4, "Potatoe", R.drawable.potatoe))
add(User(5, "Aubergine", R.drawable.aubmain))
add(User(12, "Onion", R.drawable.onion))
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="#layout/item_layout_banner"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_margin="1dp">
<androidx.cardview.widget.CardView
android:layout_width="120dp"
android:layout_height="120dp"
app:cardCornerRadius="4dp"
app:cardMaxElevation="2dp"
app:cardElevation="1dp"
android:layout_centerInParent="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="90dp"
android:layout_height="90dp"
android:scaleType="centerCrop"
android:layout_centerHorizontal="true"
app:civ_border_width= "3dp"
app:civ_border_color= "#color/colorPrimary"
android:id="#+id/imageViewAvatar"
android:src="#drawable/ic_launcher_background"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="20dp"
android:text="Veg"
android:layout_below="#+id/imageViewAvatar"
android:id="#+id/textViewUserName"
android:gravity="center"
android:layout_marginTop="5dp"
android:layout_centerHorizontal="true"
android:textColor="#000"
android:layout_marginBottom="5dp"
android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="8sp"
android:autoSizeMaxTextSize="15sp"/>
</RelativeLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
To achieve this first you have to override the getItemCount function of UsersAdapter to return a very large value such as Int.MAX_VALUE
// This enables your adapter to scroll past the actual list size
override fun getItemCount(): Int = Int.MAX_VALUE
Now change your onBindViewHolder to calculate actual position
// Lets say your list had 100 items
override fun onBindViewHolder(holder: DataViewHolder, position: Int) {
// position can be larger than 100 (ex 101), because our getItemCount doesn't return actual list size
// so if we receive position as 101, which item should we display?
// that should be item 1. (for 102 -> 2, 201 -> 1) and so on
// this suggests use of modules
val pos = position % users.size
holder.bind(users[pos]) // bind the actual item
}
Now in your MainActivity after recyclerView.adapter = adapter line, add following line
// When RV is loaded scroll it to middle, so that user doesn't hit limit on both ends(easily)
rv.scrollToPosition(Int.MAX_VALUE/2)

how to send data between activity and its fragments?

I am working on an app where click on an item in a recycler View opens another activity (Customer-Detail) where there are three Fragments in Tab layout .recycler view contains list of employees, I want to show the details of employee selected from list. I have stored All employee's data in SQLITE in "Employee" Table ( which contains Customer-Id ,Name ,Address ETC) , Now I have Customer-ID (ID of selected Customer) in "Customer-Detail" Activity. I just want to send that "Customer-ID" value to three Fragments of this Customer-Detail Activity. It seems simple but I could not find any solution . Here is my CustomerDetail.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CustomerDetail">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/custID"
/>
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<com.google.android.material.tabs.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="fill"
app:tabInlineLabel="true"
app:tabBackground="#color/lightRed"
app:tabIndicatorColor="#color/white"
app:tabTextColor="#color/white"
app:tabMode="fixed"
android:id="#+id/tablayout"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/appbar"
android:id="#+id/viewPager"
/>
</RelativeLayout>
Here is CustomerDetails.kt :
class CustomerDetail : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_customer_detail)
val extras: Bundle? = intent.extras
val EmployeeID: Int = extras!!.getInt("id")
sendToFragmentOrder(EmployeeID)
val appbar = findViewById<AppBarLayout>(R.id.appbar)
val tabLayout = findViewById<TabLayout>(R.id.tablayout)
val viewPager = findViewById<ViewPager>(R.id.viewPager)
setUpTabs()
}
private fun sendToFragmentOrder(id : Int) {
// this method is not working...
val bundle = Bundle()
bundle.putInt("id",id)
val fragmentOrder = OrderFragment()
fragmentOrder.arguments = bundle
}
private fun setUpTabs() {
val adapter = mPagerAdapter(supportFragmentManager)
adapter.addFragment(OrderFragment(), "Orders")
adapter.addFragment(ReceiptsFragment(), "Receipts")
adapter.addFragment(ReportsFragment(), "Reports")
val viewpager = findViewById<ViewPager>(R.id.viewPager)
viewpager.adapter = adapter
val tab = findViewById<TabLayout>(R.id.tablayout)
tab.setupWithViewPager(viewpager)
}
}
OrderFragment() Class :
class OrderFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val id = arguments?.getInt("id")
val view=inflater.inflate(R.layout.fragment_order, container, false)
val tv = view.findViewById<TextView>(R.id.idtv)
tv.text = id.toString()
return view }
}
i hope i explained my question well ... i am new here so ... any help will be appreciated
use the same viewmodel:
in Activity:
val viewModel: MyViewModel by viewModels()
in Fragment:
val viewModel: MyViewModel by activityViewModels()
needs ktx artifcats, see https://developer.android.com/topic/libraries/architecture/viewmodel

Handeling multiple User Interfaces with different bottom navigations in Android Studio

I am developing an app where there are different user interfaces depending on what kind of client u are. I wanted to create different Bottom Navigations depending on what type of user is logged in. The if- clause works, so the Log tells me the correct user type but I am getting a fatal exception because it tells me that the id of the second bottom navigation is not existent, but like the first one works. I now it's not the cleanest way to do so but I couldn't find a different way. Here is my code:
This is the main.kt
class MainActivity : AppCompatActivity() {
lateinit var homeFragment: HomeFragment
lateinit var mapsFragment: MapsFragment
lateinit var profil: Profil
lateinit var chat: Chat
lateinit var homeFoto: HomeFoto
val COARSE_LOCATION_RQ = 101
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val mAuth = FirebaseAuth.getInstance()
lateinit var mDatabase : DatabaseReference
val user = mAuth.currentUser
val uid = user!!.uid
var snapshot: DataSnapshot
var anwender = "Suchender"
mDatabase = FirebaseDatabase.getInstance().getReference("User").child(uid)
//Log.e("keyKey",mDatabase.database.getReference("Anwendertyp").child(anwender).toString())
mDatabase!!.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists() && snapshot.child("Anwendertyp").value.toString() == "Suchender" ){
Log.e("keyKey",snapshot.child("Anwendertyp").value.toString())
//findNavController(R.id.suchenderNavigation)
var bottomnav = findViewById<BottomNavigationView>(R.id.BottomNavMenu)
bottomnav.setOnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_home -> {
homeFragment = HomeFragment()
supportFragmentManager
.beginTransaction()
.replace(R.id.frameLayout, homeFragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
R.id.mapsFragment -> {
mapsFragment = MapsFragment()
supportFragmentManager
.beginTransaction()
.replace(R.id.frameLayout, mapsFragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
R.id.navigation_notifications -> {
profil = Profil()
supportFragmentManager
.beginTransaction()
.replace(R.id.frameLayout, profil)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
}
true
}
}
else{
setContentView(R.layout.startseite_fotografvideograf)
Log.e("key",snapshot.child("Anwendertyp").value.toString())
// Navigation.findNavController(HomeFoto().requireActivity(), R.id.navigation_home_fotografvideograf)
//findNavController(R.id.fotografNavigation)
//This is the variable that triggers the fatal exception
var bottomn = findViewById<BottomNavigationView>(R.id.bottomNavFoto)
Log.e("heyo", bottomn.toString())
bottomn.setOnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_home_fotografvideograf -> {
homeFoto = HomeFoto()
supportFragmentManager
.beginTransaction()
.replace(R.id.frameLayout, homeFoto)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
R.id.navigation_notifications -> {
profil = Profil()
supportFragmentManager
.beginTransaction()
.replace(R.id.frameLayout, profil)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
R.id.chatchat -> {
chat = Chat()
supportFragmentManager
.beginTransaction()
.replace(R.id.frameLayout, chat)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
}
true
}
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
This is the main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E8E8E8">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="30dp"
android:background="#drawable/buttom_bg"
android:elevation="2dp"
app:itemIconSize="30dp"
app:itemIconTint="#drawable/item_selector"
app:itemRippleColor="#android:color/transparent"
app:labelVisibilityMode="unlabeled"
app:menu="#menu/bottom_nav_menu" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavFoto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="30dp"
android:background="#drawable/buttom_bg"
android:elevation="2dp"
app:itemIconSize="30dp"
app:itemIconTint="#drawable/item_selector"
app:itemRippleColor="#android:color/transparent"
app:labelVisibilityMode="unlabeled"
app:menu="#menu/bottom_nav_fotograf" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
And here is the xml of the second bottom navigation:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/BottomNavFotograf"
>
<item
android:id="#+id/navigation_home_fotografvideograf"
android:icon="#drawable/ic_home_black_24dp"
android:title="#string/title_home" />
<item
android:id="#+id/navigation_notifications"
android:icon="#drawable/ic_baseline_person_24"
android:title="#string/profil" />
<item
android:id="#+id/chatchat"
android:icon="#drawable/ic_chat"
android:title="Chat" />
</menu>
Update
This is the FATAL EXCEPTION I'm getting:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.discoverme, PID: 4430 java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.google.android.material.bottomnavigation.BottomNavigationView.toString()' on a null object reference at com.example.discoverme.MainActivity$onCreate$1.onDataChange(MainActivity.kt:114) at com.google.firebase.database.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:75) at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63) at – Luzie Ewert 19 hours ago Delete
com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154)
like, it's so confusing. I know it has to be something with the id's or the fact that there can not be two bottom navigations in one layout but I can't help myself any other way and I can't tell where the first id of the first bottom navigation is coming from, because it is nowhere declared and if I'm using one of the id's I used in the xml's the app crashes and I am getting trhe same fatal (axception that tells me the reference is on a null object.
okay so update: I found the correct id. Apparently there have been two existing main.xml files and I had to delete one, but now I am only getting one of the bottom navigations, no matter what user (wether searching person or photographer) is logged in. The question is still, how can I separate them?
Here is the updated xml:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E8E8E8">
<FrameLayout
android:id="#+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/BottomNavMenu"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_margin="30dp"
android:background="#drawable/buttom_bg"
android:elevation="2dp"
app:itemIconSize="30dp"
app:itemIconTint="#drawable/item_selector"
app:itemRippleColor="#android:color/transparent"
app:labelVisibilityMode="unlabeled"
app:menu="#menu/bottom_nav_menu"
tools:ignore="MissingConstraints">
</com.google.android.material.bottomnavigation.BottomNavigationView>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavFoto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="30dp"
android:background="#drawable/buttom_bg"
android:elevation="2dp"
app:itemIconSize="30dp"
app:itemIconTint="#drawable/item_selector"
app:itemRippleColor="#android:color/transparent"
app:labelVisibilityMode="unlabeled"
app:layout_constraintBottom_toBottomOf="#+id/frameLayout"
app:menu="#menu/bottom_nav_fotograf"
tools:ignore="MissingConstraints"
tools:layout_editor_absoluteX="30dp"></com.google.android.material.bottomnavigation.BottomNavigationView>
</androidx.constraintlayout.widget.ConstraintLayout>
Okay, I managed it by outsourcing the bottom navigations in new activities and starting those in the if-clause of the main activity.kt with new layouts.

Resources