Populate UI from a ViewModel in Kotlin - android

This is the first time I am using Android Architecture. I have decided to go with MVVM structure but I am stuck at the point where I have no idea how to set the textViews in my XML with the data I pull from the database.
Checking the logs, I have seen that the function calls to my database (Firestore) does retrieve the correct data documents. Do I set the UI elements from the Activity,ViewModel or the Fragment? (Please note that I'm using a Navigation bar and controller)
Please assist me, my code is as follows:
My Single Activity:
class HomeActivity : AppCompatActivity() {
// Create the three objects for the fragments
lateinit var homeFragment: HomeFragment
lateinit var visitsFragment: VisitsFragment
lateinit var profileFragment: ProfileFragment
// ViewModels
lateinit var customerViewModel: CustomerViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
// Initialize the bottom nav bar and navigation controller and then merge them
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.btm_nav)
val navigationController = findNavController(R.id.fragmentHost)
bottomNavigationView.setupWithNavController(navigationController)
// Create app bar config object so that you can rename the bar ontop with the tab name
val appBarConfiguration = AppBarConfiguration(setOf(R.id.homeFragment,R.id.visitsFragment,R.id.profileFragment))
setupActionBarWithNavController(navigationController,appBarConfiguration)
// View Model
customerViewModel = ViewModelProvider(this).get(CustomerViewModel::class.java)
customerViewModel.retrieveCustomer().observe(this, Observer { it })
}
// This function creates the menu object by inflating it with the resource we gave it (menu resource).
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_main,menu);
return true
}
// This function checks which menu item was selected and performs the task associated with the item selected.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId;
// If Log Out menu item was selected
if (id == R.id.menuLogOut){
// Sign the user out
FirebaseAuth.getInstance().signOut()
// Finish this activity
finish()
// Start the initial activity
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
// Display the message to the user
Toast.makeText(this, "Successfully Signed Out", Toast.LENGTH_SHORT).show()
return true
}
return super.onOptionsItemSelected(item)
}
}
My View Model:
class CustomerViewModel: ViewModel() {
val TAG = "CustomerViewModel"
var db = Firebase.firestore
var user = FirebaseAuth.getInstance().currentUser
var liveData = MutableLiveData<List<Customer>>()
var cusArray = arrayListOf<Customer>()
var docRef = user?.uid
fun retrieveCustomer(): MutableLiveData<List<Customer>>
{
db.collection("users").document(docRef.toString())
.get()
.addOnSuccessListener { document ->
if (document != null)
{
val data = document
// Set the data
val name = data.get("name") as String
val surname = data.get("surname") as String
val email = data.get("email") as String
val contactNo = data.get("contact no") as String
val customer = Customer(name, surname, email, contactNo)
cusArray.add(customer)
liveData.value = cusArray
Log.d(TAG, "DocumentSnapshot data: ${document.data}")
}
else
{
Log.d(TAG, "No such document")
}
}
.addOnFailureListener { exception ->
Log.d(TAG, "get failed with " + exception.message, exception)
}
return liveData
}
}
My Object Class
package com.CleanWheels.cleanwheels.DataClasses
data class Customer(
val name: String?,
val surname: String?,
val email: String?,
val contactNo: String?
)
My XML file (profile_fragment):
<?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=".Fragments.ProfileFragment">
<TextView
android:id="#+id/banner"
android:layout_width="499dp"
android:layout_height="290dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="-6dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="0dp"
android:background="#color/colorPrimary"
android:layout_marginLeft="-6dp"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true"
android:layout_marginRight="0dp" />
<ImageView
android:id="#+id/image"
android:layout_width="154dp"
android:layout_height="159dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="53dp"
android:layout_marginEnd="132dp"
android:layout_marginRight="132dp"
android:layout_marginBottom="78dp"
android:src="#drawable/ic_action_profile" />
<LinearLayout
android:id="#+id/layout_1"
android:layout_width="280dp"
android:layout_height="40dp"
android:layout_below="#id/banner"
android:layout_marginLeft="80dp"
android:layout_marginTop="100dp"
android:layout_marginRight="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Name:"
android:textSize="18sp"/>
<TextView
android:id="#+id/profileNameUI"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="18sp"/>
</LinearLayout>
<LinearLayout
android:id="#+id/layout_2"
android:layout_width="280dp"
android:layout_height="40dp"
android:layout_below="#id/layout_1"
android:layout_marginLeft="80dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Surname:"
android:textSize="18sp"/>
<TextView
android:id="#+id/profileSurnameUI"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="18sp"/>
</LinearLayout>
<LinearLayout
android:id="#+id/layout_3"
android:layout_width="280dp"
android:layout_height="40dp"
android:layout_below="#id/layout_2"
android:layout_marginLeft="80dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Email Address:"
android:textSize="18sp"/>
<TextView
android:id="#+id/profileEmailUI"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="18sp"/>
</LinearLayout>
<LinearLayout
android:id="#+id/layout_4"
android:layout_width="280dp"
android:layout_height="40dp"
android:layout_below="#id/layout_3"
android:layout_marginLeft="80dp"
android:layout_marginBottom="50dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Contact No:"
android:textSize="18sp" />
<TextView
android:id="#+id/profileContactUI"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:id="#+id/layout_5"
android:layout_width="65dp"
android:layout_height="220dp"
android:layout_below="#id/banner"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="0dp"
android:layout_marginLeft="0dp"
android:layout_marginTop="90dp"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:src="#drawable/ic_action_profile_name_ui"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:src="#drawable/ic_action_profile_surname_ui"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:src="#drawable/ic_action_profile_email_ui"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="0dp"
android:layout_weight="1"
android:src="#drawable/ic_action_profile_contact_ui"/>
</LinearLayout>
The profile_fragment class file:
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [ProfileFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class ProfileFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_profile, container, false)
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment ProfileFragment.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
ProfileFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
Then finally, the View I am trying to populate

You need to move all the logic to ProfileFragment once you navigate to ProfileFragment data will be set.
Example:
ProfileFragment
class ProfileFragment : Fragment() {
private val customerViewModel: CustomerViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_profile, container, false)
val name = view.findViewById<TextView>(R.id.name)
val surname = view.findViewById<TextView>(R.id.surname)
val email = view.findViewById<TextView>(R.id.email)
val contact = view.findViewById<TextView>(R.id.contact)
//calling initially here
customerViewModel.retrieveCustomer()
customerViewModel.liveData.observe(viewLifecycleOwner, Observer {
//customer index at 0
val customer = it[0]
name.text = customer.name
surname.text = customer.surname
email.text = customer.email
contact.text = customer.contactNo
})
return view
}
CustomerViewModel.kt
class CustomerViewModel(application: Application) : AndroidViewModel(application) {
var liveData = MutableLiveData<List<Customer>>()
fun retrieveCustomer(){
//Your logic to get data from Firebase or any remote or db
val listOfCustomer = mutableListOf<Customer>()
val customer = Customer("name", "surname","email", "contqct")
listOfCustomer.add(customer)
liveData.postValue(listOfCustomer)
}
}
fragment_profile.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/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Name"
android:padding="8dp"
android:textSize="24dp"
/>
<TextView
android:id="#+id/surname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Surname"
android:padding="8dp"
android:textSize="24dp"
/>
<TextView
android:id="#+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Name"
android:padding="8dp"
android:textSize="24dp"
/>
<TextView
android:id="#+id/contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Name"
android:padding="8dp"
android:textSize="24dp"
/>
</LinearLayout>

Related

How to display Fullscreen image from RecyclerView in Kotlin?

i am getting data from API and display it in RecyclerView and everything is working fine
but now i'm a bit confused on how can i display the images that i'm getting from the API in full screen if the user clicked on it
this is the activity:
LlmNoteDetailsActivity:
class LlmNoteDetailsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_ilm_note_detail)
val EventName = intent.getStringExtra("EventName")
val EventLink = intent.getStringExtra("EventLink")
val isFavourite = intent.getBooleanExtra("isFavourite" , false)
val eventId = intent.getIntExtra("eventId",0)
val eventDate = intent.getStringExtra("eventDate")
val eventDescription = intent.getStringExtra("eventDescription")
val eventLocation = intent.getStringExtra("eventLocation")
val eventLink = intent.getStringExtra("eventLink")
val EventImage = intent.getStringExtra("EventImage")
val ImageViewTop: ImageView = findViewById(R.id.ImageViewTop)
val LinkText: TextView = findViewById(R.id.LocationTx)
val EventNameText: TextView = findViewById(R.id.EventNameText)
val eventDateTxt: TextView = findViewById(R.id.eventDateTxt)
val eventDescriptionText: TextView = findViewById(R.id.eventDescriptionText)
val butttoRegiiste: Button = findViewById(R.id.butttoRegiiste)
val detailback_btn: ImageButton = findViewById(R.id.detailback_btn)
LinkText.text = EventLink
EventNameText.text = EventName
eventDateTxt.text = eventDate
eventDescriptionText.text = eventDescription
butttoRegiiste.setOnClickListener {
openLinkInBrowser(eventLink!!)
}
detailback_btn.setOnClickListener {
onBackPressed()
}
ImageViewTop.setOnClickListener {
//display image in fullscreen
}
Picasso.get()
.load(EventImage)
.error(R.drawable.qiblacompass)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.into(ImageViewTop)
}
fun openLinkInBrowser(url: String) {
try {
val url = if (Uri.parse(url).scheme == null || !url.startsWith("https://") && !url.startsWith(
"http://"
)) {
"https://$url"
} else url
val webPage: Uri = Uri.parse(url)
val intent = Intent(Intent.ACTION_VIEW, webPage)
this.startActivity(intent)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
this its layout(fragment_ilm_note_detail):
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
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="wrap_content"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_marginTop="-100dp"
android:id="#+id/ImageViewTop"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:contentDescription="login background"
android:src="#drawable/sampledetail" />
<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="350dp"
android:layout_alignParentBottom="true"
android:orientation="vertical"
app:flexDirection="column">
<LinearLayout
android:background="#drawable/rounded_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="#dimen/dimen_16"
android:paddingLeft="#dimen/dimen_16"
android:paddingRight="#dimen/dimen_16"
android:elevation="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="vertical"
android:padding="20dp">
<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
app:justifyContent="space_between"
android:layout_height="wrap_content">
<com.google.android.flexbox.FlexboxLayout
app:alignItems="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_marginRight="10dp"
android:src="#drawable/pin"
android:layout_width="18dp"
android:layout_height="25dp"/>
<TextView
android:id="#+id/LocationTx"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/poppins"
android:text="Ara Damansara"
android:textColor="#color/black"
android:textSize="15sp" />
</com.google.android.flexbox.FlexboxLayout>
<ImageView
android:layout_marginRight="10dp"
android:src="#drawable/star"
android:layout_width="25dp"
android:layout_height="25dp"/>
</com.google.android.flexbox.FlexboxLayout>
<TextView
android:id="#+id/EventNameText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:fontFamily="#font/poppins"
android:text="Perfecting My Solah"
android:textColor="#color/teal_600"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/eventDateTxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:fontFamily="#font/poppins_semibold"
android:text="Sabtu 15 Ogos 2021"
android:textColor="#color/black"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:id="#+id/eventDescriptionText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:fontFamily="#font/poppins"
android:text=""
android:textColor="#color/black"
android:textSize="10sp" />
<Button
android:id="#+id/butttoRegiiste"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginVertical="#dimen/dimen_32"
android:backgroundTint="#FFB248"
android:textAllCaps="false"
android:text="Link to Register"
app:rippleColor="#FFB248" />
</LinearLayout>
</LinearLayout>
</com.google.android.flexbox.FlexboxLayout>
<ImageButton
android:id="#+id/detailback_btn"
android:layout_width="18dp"
android:layout_marginLeft="#dimen/_20sdp"
android:layout_marginTop="#dimen/_50sdp"
android:layout_height="20dp"
android:background="#drawable/chevron_left" />
</RelativeLayout>
</ScrollView>
this is the adapter:
IimfinderAdapter:
class IimfinderAdapter(var countryList: List<ilmFinders>, private val iimfinderAdapterCallback: MainActivity): RecyclerView.Adapter<IimfinderAdapter.ViewHolder>(){
lateinit var context: Context
val CategoryID: Int = AppPreferences.heightInCentimeters ?: 170
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): IimfinderAdapter.ViewHolder {
context = parent.context!!
val view = LayoutInflater.from(context).inflate(R.layout.list_item2, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return countryList[CategoryID].ilmFinders.size
}
override fun onBindViewHolder(holder: IimfinderAdapter.ViewHolder, position: Int) {
var categoryIDis = countryList[CategoryID].categoryID
Log.e("CategoryID",categoryIDis.toString())
Log.e("Categorycount ",countryList[CategoryID].ilmFinders.size.toString())
holder.eventName.text = countryList[CategoryID].ilmFinders[position].eventName
holder.eventLink.text = countryList[CategoryID].ilmFinders[position].eventLink
Log.d("ggggggggggggggg", countryList[CategoryID].ilmFinders[position].eventName)
var ilmfinderimage = countryList[CategoryID].ilmFinders[position].eventPhoto.toString()
var newatri = ilmfinderimage.replace("[", "").replace("" +
"]", "")
Log.d("ffffffffff", newatri)
Picasso.get()
.load(newatri)
.error(R.drawable.qiblacompass)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.into(holder.eventPhoto)
holder.list_card.setOnClickListener {
countryList[CategoryID].ilmFinders[position].eventName
countryList[CategoryID].ilmFinders[position].eventLink
newatri
//context.startActivity(Intent(context, LlmNoteDetailsActivity::class.java))
var intent = Intent(context, LlmNoteDetailsActivity::class.java)
intent.putExtra("EventName",countryList[CategoryID].ilmFinders[position].eventName)
intent.putExtra("EventLink",countryList[CategoryID].ilmFinders[position].eventLink)
intent.putExtra("isFavourite",countryList[CategoryID].ilmFinders[position].isFavourite)
intent.putExtra("eventId",countryList[CategoryID].ilmFinders[position].eventId)
intent.putExtra("eventDate",countryList[CategoryID].ilmFinders[position].eventDate)
intent.putExtra("eventDescription",countryList[CategoryID].ilmFinders[position].eventDescription)
intent.putExtra("eventLocation",countryList[CategoryID].ilmFinders[position].eventLocation)
intent.putExtra("eventLink",countryList[CategoryID].ilmFinders[position].eventLink)
intent.putExtra("EventImage",newatri)
context.startActivity(intent)
}
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
val eventName: TextView = itemView.findViewById(R.id.title_tv2)
val eventLink: TextView = itemView.findViewById(R.id.tv_url2)
val eventPhoto: ImageView = itemView.findViewById(R.id.thumbnail_tv2)
val list_card: ConstraintLayout = itemView.findViewById(R.id.list_constraint)
}
}
and this is its layout(list_item2):
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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/frame_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.bigman.wmzx.customcardview.library.CardView
android:id="#+id/list_card"
android:layout_width="wrap_content"
android:layout_height="250dp"
app:cardCornerRadius="4dp"
app:contentPadding="8dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/list_constraint"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/thumbnail_tv2"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="#drawable/insta"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints"
/>
<TextView
android:id="#+id/title_tv2"
android:layout_width="150dp"
android:textColor="#4B4B4B"
android:fontFamily="#font/poppins"
android:textStyle="bold"
android:textSize="12dp"
android:maxLength="20"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/thumbnail_tv2" />
<TextView
android:id="#+id/tv_url2"
android:maxLength="20"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="10dp"
android:drawableLeft="#drawable/linkiimfinder"
android:layout_marginTop="8dp"
android:fontFamily="#font/poppins"
android:text="TextView"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/title_tv2"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.bigman.wmzx.customcardview.library.CardView>
</FrameLayout>
so in (fragment_ilm_note_detail) layout there is an ImageView (id:ImageViewTop) i'm trying to display this image in full screen if the user click on it
i tried to create new activity and layout to show only the image and i added setOnClickListener if the user click the image but i faced few errors
what is the easiest way to achieve this?
"please be patient with me becasue i'm new to Kotlin"
i have been searching online for almost 3 days for this problem and i couldn't find the right solution for my case that's why i'm asking here, please relate to my code if you have a solution
You don't create a new activity inside holder.list_card.setOnClickListener. Instead, create a new fragment, with it's own xml layout with fullScreen imageView. For example, the kotlin code for fragment:
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.fragment.app.Fragment
class FullScreenImageFragment: Fragment() {
companion object {
val TAG: String = "FullScreenImageFragment"
val INPUT_IMAGE: String = "INPUT_IMAGE"
fun getInstance(inputImageUrl: String): FullScreenImageFragment {
val fullScreenImageFragment = FullScreenImageFragment()
val args = Bundle()
args.putString(INPUT_IMAGE, inputImageUrl)
fullScreenImageFragment.arguments = args
return fullScreenImageFragment
}
}
private var inputImageUrl: String = ""
private lateinit var fragmentRootView: View
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// return super.onCreateView(inflater, container, savedInstanceState)
this.fragmentRootView = inflater.inflate(R.layout.full_screen_image, container, false)
this.fragmentRootView.setOnClickListener { /* empty listener to prevent click propagation */ }
return fragmentRootView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initArgument()
val imagePreview: ImageView = fragmentRootView.findViewById(R.id.imagePreview)
Picasso.get()
.load(inputImageUrl)
.error(R.drawable.qiblacompass)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.into(imagePreview)
}
private fun initArgument() {
if(arguments!=null) {
this.inputImageUrl = requireArguments().getString(INPUT_IMAGE, "")
}
}
}
The xml layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imagePreview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
And finally, inside your adapter:
holder.list_card.setOnClickListener{
val activity: Activity = holder.context as Activity
activity.supportFragmentManager.beginTransaction()
.replace(android.R.id.content, FullScreenImageFragment.getInstance(newatri)) // "www.some_image_url.com"
.commit()
}
This should do the work. Consider studying some more on fragments to further modify the code.
SOLUTION:
so what i did here:
i created new Activity with its layout:
Activity:
val detailback_btn: ImageButton = findViewById(R.id.detailback_btn2)
val EventImage = intent.getStringExtra("EventImage")
val thumbnail_tv22: ImageView = findViewById(R.id.thumbnail_tv22)
Picasso.get()
.load(EventImage)
.error(R.drawable.qiblacompass)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.into(thumbnail_tv22)
detailback_btn.setOnClickListener {
onBackPressed()
}
}
i passed the image "val EventImage = intent.getStringExtra("EventImage")"
and from "LlmNoteDetailsActivity" i added setOnClickListener to open new Activity and passed the image:
LlmNoteDetailsActivity:
ImageViewTop.setOnClickListener {
val intent = Intent(this, LoginActivityV2::class.java)
intent.putExtra("EventImage",EventImage)
startActivity(intent)
}

Fragment Layout is blank

I am passing an object (Contact) of type contacts, onclick in RecyclerView and displaying it in a Fragment in another activity using intents and Serialize. But the content is blank no fields displayed or titles.. blank layout not sure what the issue is here...
Calling the activity with fragment
holder.itemView.setOnClickListener {
val intent = Intent(context, ContactDetailsHome::class.java)
intent.putExtra("contact", contact as Serializable)
intent.putExtra("Edit", true)
context.startActivity(intent)
}
Fragment Contact Details where the layout is generated
class ContactDetails : Fragment() {
companion object {
#JvmStatic
fun start(context: Context, contact: Contact?, isEdit: Boolean) {
val starter = Intent(context, ContactDetails::class.java)
.putExtra("contact", contact as Serializable)
.putExtra("Edit", isEdit)
context.startActivity(starter)
}
}
private lateinit var contact: Contact
private lateinit var numEditList: ArrayList<EditText>
private lateinit var emailEditList: ArrayList<EditText>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
inflater.inflate(R.layout.fragment_view_contact_details, container, false)
numEditList = ArrayList()
emailEditList = ArrayList()
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (activity?.intent?.getBooleanExtra("Edit", false) == true){
initEdit()
}else{
initAdd()
}
delete_contact!!.setOnClickListener {
deleteContact()
Toast.makeText(activity, "Contact Deleted Successfully", Toast.LENGTH_SHORT).show()
activity?.finish()
}
}
private fun initEdit() {
//getting the value from the object
contact = (activity?.intent?.getSerializableExtra("contact") as Contact)
//assigning it to fields to be displayed
contDetails_name.setText(contact.name)
if (contact.numbers.isEmpty()) {
phoneTitle!!.visibility = View.GONE
}
if (contact.emails.isEmpty()) {
title_emails!!.visibility = View.GONE
}
for (number in contact.numbers) {
val editText = EditText(activity)
editText.setText(number)
editText.setTextColor(Color.parseColor("#0D0D0D"))
editText.typeface = Typeface.DEFAULT_BOLD
editText.textSize = 20f
editText.isEnabled = false
numEditList.add(editText)
contact_numbers_layout!!.addView(editText)
}
for (email in contact.emails) {
val editText = EditText(activity)
editText.setText(email)
editText.setTextColor(Color.parseColor("#0D0D0D"))
editText.typeface = Typeface.DEFAULT_BOLD
editText.textSize = 20f
editText.isEnabled = false
emailEditList.add(editText)
contact_emails_layout!!.addView(editText)
}
edit_contact!!.setOnClickListener {
if (contDetails_name.isEnabled) {
if (contDetails_name.text.toString().isEmpty()) {
Toast.makeText(activity, "Contact name can't be empty", Toast.LENGTH_SHORT)
.show()
}
contDetails_name.isEnabled = false
for (editText in numEditList) {
editText.isEnabled = false
}
for (editText in emailEditList) {
editText.isEnabled = false
}
deleteContact()
addContact()
edit_contact.text = "Edit"
Toast.makeText(activity, "Contact updated successfully", Toast.LENGTH_SHORT).show()
} else {
contDetails_name.isEnabled = true
for (editText in numEditList) {
editText.isEnabled = true
}
for (editText in emailEditList) {
editText.isEnabled = true
}
edit_contact.text = "Save"
}
}
}
layout file
<ScrollView 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=".Contacts.ui.ContactDetails">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:padding="10dp"
app:cardCornerRadius="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="8dp"
android:text="Name"
android:textAllCaps="true"
android:textSize="16sp" />
<EditText
android:id="#+id/contDetails_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:enabled="false"
android:hint="Contact Name"
android:inputType="textPersonName"
android:textColor="#color/txtcolor"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="#+id/phoneTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:layout_marginTop="8dp"
android:text="Phone/Mobile No:"
android:textAllCaps="true"
android:visibility="visible"
android:textSize="16sp" />
<LinearLayout
android:id="#+id/contact_numbers_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:orientation="vertical" />
<TextView
android:id="#+id/title_emails"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:layout_marginTop="8dp"
android:text="Email"
android:textAllCaps="true"
android:textSize="16sp" />
<LinearLayout
android:id="#+id/contact_emails_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:orientation="vertical" />
<Button
android:id="#+id/edit_contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="30dp"
android:layout_marginTop="20dp"
android:background="#color/colorPrimary"
android:text="Edit"
android:textColor="#fff"
android:textSize="20sp" />
<Button
android:id="#+id/delete_contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="30dp"
android:layout_marginTop="20dp"
android:background="#color/colorPrimary"
android:layout_marginBottom="8dp"
android:text="Delete"
android:textColor="#fff"
android:textSize="20sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
discovered that I didn't declare view during creation in oncreateView before returning it. resulting in no view being generated hence blank fragment.
Val view:View = ....
return view

how to call any activity from fragment Android Studio Kotlin [duplicate]

This question already has answers here:
Kotlin: open new Activity inside of a Fragment
(15 answers)
Closed 2 years ago.
can i call another Activity From Fragment Button ?
I have seen all the problems in stackoverflow, but have not found a solution.
this my fragment code from MainActivity
package com.example.apptest
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_home.*
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [HomeFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class HomeFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
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)
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment HomeFragment.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
HomeFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
and this is my fragment xml code
<?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=".HomeFragment">
<TextView
android:textColor="#34495e"
android:textSize="20sp"
android:layout_marginTop="100dp"
android:id="#+id/mytitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:text="BELAJAR BERSAMA NATSUZD"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:textColor="#34495e"
android:textSize="20sp"
android:id="#+id/japantitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="日本語"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/mytitle" />
<Button
style="#style/Widget.AppCompat.Button.Colored"
android:textColor="#34495e"
android:layout_marginTop="50dp"
android:id="#+id/buttonImage"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:background="#drawable/custome_button"
android:drawableStart="#drawable/book50"
android:drawableLeft="#drawable/book50"
android:gravity="center"
android:padding="15dp"
android:text="KOSAKATA"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/japantitle"
tools:ignore="OnClick" />
<Button
style="#style/Widget.AppCompat.Button.Colored"
android:textColor="#34495e"
android:text="BELAJAR SOAL"
android:gravity="center"
android:textSize="15sp"
android:textStyle="bold"
android:padding="15dp"
android:drawablePadding="15dp"
android:drawableLeft="#drawable/exam"
android:layout_marginRight="50dp"
android:layout_marginLeft="50dp"
android:layout_marginTop="20dp"
android:id="#+id/buttonImage1"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#drawable/custome_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/buttonImage"
android:drawableStart="#drawable/exam" />
<Button
style="#style/Widget.AppCompat.Button.Colored"
android:textColor="#34495e"
android:text="PERCAKAPAN"
android:gravity="center"
android:textSize="15sp"
android:padding="15dp"
android:textStyle="bold"
android:drawablePadding="15dp"
android:drawableLeft="#drawable/chat"
android:layout_marginRight="50dp"
android:layout_marginLeft="50dp"
android:layout_marginTop="20dp"
android:id="#+id/buttonImage2"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#drawable/custome_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/buttonImage1"
android:drawableStart="#drawable/chat" />
<Button
style="#style/Widget.AppCompat.Button.Colored"
android:textColor="#34495e"
android:text="POLA KALIMAT"
android:gravity="center"
android:textSize="15sp"
android:padding="15dp"
android:textStyle="bold"
android:drawablePadding="15dp"
android:drawableLeft="#drawable/variable"
android:layout_marginRight="50dp"
android:layout_marginLeft="50dp"
android:layout_marginTop="20dp"
android:id="#+id/buttonImage3"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#drawable/custome_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/buttonImage2"
android:drawableStart="#drawable/variable" />
</androidx.constraintlayout.widget.ConstraintLayout>
and this is my second activity ( target activity )
package com.example.apptest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class SoalActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_soal)
}
}
how do I connect to the second activity using the button in the fragment
Sure you can.
In order to launch an activity from your fragment, override the onViewCreated() method in your fragment. Inside it, type:
buttonImage2.setOnClickListener {
val intent = Intent(context, SoalActivity::class.java)
startActivity(intent)
}
And that's it :)

Android Binding Adapter attribute not found

I am using a binding adapter to have mutable text in one of my views. I believe I have it implemented correctly (and it's working in other places), but for the case of mutableText, it's getting the error AAPT: error: attribute mutableText not found
I've looked through some other answers on here, but none of them have been able to solve the issue.
Here is my layout file:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.example.nhlstats.ui.game.GameViewModel" />
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/awayTeam"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="12dp">
<ImageView
android:id="#+id/awayTeamLogo"
android:layout_height="48dp"
android:layout_width="0dp"
android:layout_weight="1"
tools:src="#drawable/ic_launcher_background"/>
<TextView
android:id="#+id/awayTeamName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:layout_gravity="center_vertical"
app:mutableText="#{viewModel.getAwayTeamName()}"
tools:text="CHI Blackhawks"/>
<TextView
android:id="#+id/awayScore"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
app:mutableText="#{viewModel.getAwayTeamScore().toString()}"
tools:text="0"/>
<TextView
android:id="#+id/gameTime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
app:mutableText="#{viewModel.getTimeRemaining()"
tools:text="14:26 3rd"/>
</LinearLayout>
<LinearLayout
android:id="#+id/homeTeam"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp">
<ImageView
android:id="#+id/homeTeamLogo"
android:layout_height="48dp"
android:layout_width="0dp"
android:layout_weight="1"
tools:src="#drawable/ic_launcher_background"/>
<TextView
android:id="#+id/homeTeamName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:layout_gravity="center_vertical"
app:mutableText="#{viewModel.getHomeTeamName()}"
tools:text="CAR Hurricanes"/>
<TextView
android:id="#+id/homeScore"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="2"
app:mutableText="#{viewModel.getHomeTeamScore().toString()}"
tools:text="4"/>
</LinearLayout>
</LinearLayout>
</layout>
and my BindingAdpater function:
#BindingAdapter("mutableText")
fun setMutableText(view: TextView, text: MutableLiveData<String>?) {
val parentActivity:AppCompatActivity? = view.getParentActivity()
if (parentActivity != null && text != null) {
text.observe(parentActivity, Observer { value ->
view.text = value?:""
})
}
}
GameViewModel:
class GameViewModel:BaseViewModel() {
private val awayTeamName = MutableLiveData<String>()
private val homeTeamName = MutableLiveData<String>()
private val awayTeamScore = MutableLiveData<Int>()
private val homeTeamScore = MutableLiveData<Int>()
private val timeRemaining = MutableLiveData<String>()
fun bind(response: Game) {
awayTeamName.value = response.gameData.teams.get(0).name
homeTeamName.value = response.gameData.teams.get(1).name
awayTeamScore.value = response.liveData.linescore.teams.get(1).goals
homeTeamScore.value = response.liveData.linescore.teams.get(0).goals
timeRemaining.value = response.liveData.linescore.currentPeriodOrdinal + " " + response.liveData.linescore.currentPeriodTimeRemaining
}
fun getAwayTeamName(): MutableLiveData<String> {
return awayTeamName
}
fun getHomeTeamName(): MutableLiveData<String> {
return homeTeamName
}
fun getAwayTeamScore(): MutableLiveData<Int> {
return awayTeamScore
}
fun getHomeTeamScore(): MutableLiveData<Int> {
return homeTeamScore
}
fun getTimeRemaining(): MutableLiveData<String> {
return timeRemaining
}
}
MainActivity:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: GameListViewModel
private var errorSnackbar: Snackbar? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.gameList.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
viewModel = ViewModelProviders.of(this).get(GameListViewModel::class.java)
viewModel.errorMessage.observe(this, Observer { errorMessage ->
if (errorMessage != null)
showError(errorMessage)
else
hideError()
})
binding.viewModel = viewModel
}
private fun showError(#StringRes errorMessage:Int) {
errorSnackbar = Snackbar.make(binding.root, errorMessage, Snackbar.LENGTH_INDEFINITE)
errorSnackbar?.setAction(R.string.retry, viewModel.errorClickListener)
errorSnackbar?.show()
}
private fun hideError() {
errorSnackbar?.dismiss()
}
}
Thanks in advance.
As per your GameViewModel, I don't think you need any custom binding adapter.
Please check the edited code.
GameViewModel
class GameViewModel:BaseViewModel() {
// Make the variables public and access directly instead of exposing them via get() method.
val awayTeamName = MutableLiveData<String>()
val homeTeamName = MutableLiveData<String>()
val awayTeamScore = MutableLiveData<String>() // Change to String
val homeTeamScore = MutableLiveData<String>() // Change to String
val timeRemaining = MutableLiveData<String>()
fun bind(response: Game) {
awayTeamName.value = response.gameData.teams.get(0).name
homeTeamName.value = response.gameData.teams.get(1).name
awayTeamScore.value = response.liveData.linescore.teams.get(1).goals.toString() // Convert to String from here only instead of writing it in XML!
homeTeamScore.value = response.liveData.linescore.teams.get(0).goals.toString()
timeRemaining.value = response.liveData.linescore.currentPeriodOrdinal + " " + response.liveData.linescore.currentPeriodTimeRemaining
}
}
Your layout file(Notice I accessed the variables directly and removed the toString() as we are now only exposing MutableLiveData with String and yes, we are not using your custom binding adapter.
<data>
<variable
name="viewModel"
type="com.example.nhlstats.ui.game.GameViewModel" />
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/awayTeam"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="12dp">
<ImageView
android:id="#+id/awayTeamLogo"
android:layout_height="48dp"
android:layout_width="0dp"
android:layout_weight="1"
tools:src="#drawable/ic_launcher_background"/>
<TextView
android:id="#+id/awayTeamName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:layout_gravity="center_vertical"
android:text="#{viewModel.awayTeamName}"
tools:text="CHI Blackhawks"/>
<TextView
android:id="#+id/awayScore"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:text="#{viewModel.awayTeamScore}"
tools:text="0"/>
<TextView
android:id="#+id/gameTime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:text="#{viewModel.timeRemaining}"
tools:text="14:26 3rd"/>
</LinearLayout>
<LinearLayout
android:id="#+id/homeTeam"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp">
<ImageView
android:id="#+id/homeTeamLogo"
android:layout_height="48dp"
android:layout_width="0dp"
android:layout_weight="1"
tools:src="#drawable/ic_launcher_background"/>
<TextView
android:id="#+id/homeTeamName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:layout_gravity="center_vertical"
android:text="#{viewModel.homeTeamName}"
tools:text="CAR Hurricanes"/>
<TextView
android:id="#+id/homeScore"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="2"
android:text="#{viewModel.homeTeamScore}"
tools:text="4"/>
</LinearLayout>
</LinearLayout>
I haven't tested this so let me know how this goes for you.
Your binding adapter receives a nullable value, while the viewModel returns a non-null value. Change the text parameter to be non-null, just like the function in the viewModel returns it.
You can also do shorter encapsulation, for example:
private val _data = MutableLiveData<String>()
val data: LiveData<String>
get() = _data
This way you don't have to write long and boring getters like in Java.

Android LinearLayout Gone don't update automatically

I have a form that it could be submitted and send the data to an API, so when I receive the callback of request done I would like to hide the form and show a view of thanks.
This is my layout :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:orientation="vertical"
android:animateLayoutChanges="true">
<LinearLayout
android:id="#+id/thank_you_layout_rate"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="20dp"
android:src="#drawable/ic_check_circle_green_800_48dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="5dp"
android:fontFamily="#font/roboto_medium"
android:gravity="center"
android:text="#string/thank_you_for_rating"
android:textAppearance="#android:style/TextAppearance.Material.Large"
android:textColor="#color/DarkBlue"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="#+id/form_rating"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="visible">
<TextView
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="5dp"
android:layout_weight="0.1"
android:fontFamily="#font/roboto_medium"
android:gravity="center"
android:text="#string/rate_our_app"
android:textAppearance="#android:style/TextAppearance.Material.Large"
android:textColor="#color/DarkBlue"
android:textStyle="bold" />
<RatingBar
android:id="#+id/ratingbar_rate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="5dp"
android:isIndicator="false"
android:numStars="5"
android:rating="4"
android:stepSize="1" />
<View
android:id="#+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="10dp"
android:background="?android:attr/listDivider" />
<EditText
android:hint="#string/rate_our_app"
android:id="#+id/comment_rate"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.8"
android:inputType="textMultiLine"
android:textAppearance="#android:style/TextAppearance.Material.Large"
android:textColor="#color/DarkBlue"
/>
<Button
android:id="#+id/save_rate"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginEnd="30dp"
android:layout_marginStart="30dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="15dp"
android:layout_weight="0.1"
android:background="#color/DecathlonBlue"
android:fontFamily="#font/roboto_medium"
android:gravity="center"
android:text="#string/save"
android:textAlignment="center"
android:textAppearance="#android:style/TextAppearance.Material.Large"
android:textColor="#color/LightGrey"
android:textAllCaps="true"/>
</LinearLayout>
</LinearLayout>
and this is my fragment :
class RateFragment : Fragment(), RateFragmentListener {
private lateinit var mLoginManager: LoginManager
private lateinit var loadingDialog: LoadingDialog
private lateinit var ratePresenter: RatePresenter
private lateinit var mView: View
private lateinit var rateNotAllowed: LinearLayout
private lateinit var formRating: LinearLayout
companion object {
fun newInstance(loginManager: LoginManager): Fragment {
val currentFragment = RateFragment()
currentFragment.mLoginManager = loginManager
return currentFragment
}
}
override fun onResume() {
this.stopLoadingDialog()
super.onResume()
}
/**
*
* #param inflater LayoutInflater
* #param container ViewGroup?
* #param savedInstanceState Bundle?
* #return View?
*/
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
mView = inflater.inflate(R.layout.rate_fragment, container, false)
val saveButton = mView.findViewById<Button>(R.id.save_rate)
val starBar = mView.findViewById<RatingBar>(R.id.ratingbar_rate)
val commentRate = mView.findViewById<EditText>(R.id.comment_rate)
rateNotAllowed = mView.findViewById(R.id.thank_you_layout_rate)
formRating = mView.findViewById(R.id.form_rating)
loadingDialog = LoadingDialog(context!!)
startLoadingDialog()
initPresenter(activity as Activity, this)
saveButton.setOnClickListener {
this.startLoadingDialog()
ratePresenter.sendRating(
commentRate.text.toString(),
starBar.rating
)
}
return mView
}
/**
*
* #param activity Activity
*/
private fun initPresenter(
activity: Activity,
rateFragment: RateFragment
) {
ratePresenter = RatePresenter(activity, mLoginManager, rateFragment)
}
/**
* Loading dialog, block the UI
*/
override fun stopLoadingDialog() {
loadingDialog.dismiss()
}
/**
* Loading dialog, block de UI
*/
override fun startLoadingDialog() {
loadingDialog.show()
}
override fun rateSent() {
stopLoadingDialog()
}
override fun rateError() {
activity!!.toast("error on sending the rating")
stopLoadingDialog()
}
override fun rateNotAllowed() {
formRating.visibility = View.GONE
rateNotAllowed.visibility = View.VISIBLE
}
}
But the update of the view isn't done automatically only if I change the vie and come back to it ( there is an if inside the presenter that check if a note is sent or not ).
Thank you, regards

Categories

Resources