I'm making a music app. I have a recyclerview and I am playing clicked item's music, at the same time animation works too. Question is whenever user change the recyclerview's item position I need to cancel first animation and start new one for new position. I mean every time will be just 1 animation exist.
My RecyclerViewAdapter
class RecyclerViewAdapter(private val ModelList:List<Musics>,private val listener:
ClickListener) :RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>(){
class ViewHolder(var binding:GridListBinding):RecyclerView.ViewHolder(binding.root) {
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = DataBindingUtil.inflate<GridListBinding>(inflater,R.layout.grid_list,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: RecyclerViewAdapter.ViewHolder, position: Int) {
holder.binding.musics = ModelList[position]
holder.binding.constraint.setOnClickListener{
listener.buttonClicked(holder.binding.constraint,ModelList[position],position)
}
}
override fun getItemCount(): Int {
return ModelList.size
}
}
My ClickListener for adapter
interface ClickListener {
fun buttonClicked(view: View,model: Musics,position:Int)
}
grid_list for recyclerviewAdapter
<?xml version="1.0" encoding="utf-8"?>
<layout
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"
>
<data>
<variable
name="musics"
type="com.tunahan.musicplayer.model.Musics" />
<variable
name="listener"
type="com.tunahan.musicplayer.adapter.ClickListener" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="125dp"
android:id="#+id/constraint"
android:layout_height="125dp"
android:layout_marginTop="10dp"
android:layout_marginStart="5dp"
tools:layout_editor_absoluteX="52dp"
tools:layout_editor_absoluteY="42dp"
>
<ImageView
android:id="#+id/image"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/linearLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:src="#drawable/musical"
tools:ignore="ContentDescription"
/>
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="bottom"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TextView
android:id="#+id/gridTextView"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:fontFamily="#font/allerta"
android:gravity="center"
android:paddingStart="5dp"
android:text="#{musics.filename}"
android:textColor="#color/black"
android:textSize="16sp"
tools:ignore="RtlSymmetry" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
And Pulse Animation for gridlist's imageView
scaleDown = ObjectAnimator.ofPropertyValuesHolder(
view.image,
PropertyValuesHolder.ofFloat("scaleX", 1.1f),
PropertyValuesHolder.ofFloat("scaleY", 1.1f),
)
scaleDown.duration = 500
scaleDown.repeatCount = ObjectAnimator.INFINITE
scaleDown.repeatMode = ObjectAnimator.REVERSE
scaleDown.start()
ClickListener
override fun buttonClicked(view: View, model: Musics, position: Int) {
path = model.filepath
nextMusic = position
positionplus = position
handler.removeCallbacks(runnable)
saveduid = sharedPref.getInt("changed", model.uid)
editor = sharedPref.edit()
editor.putInt("changed", model.uid)
editor.apply()
editor2.putInt("positionplus", positionplus)
editor2.apply()
if (saveduid == model.uid) {
if (mediaPlayer.isPlaying) {
ForegroundService.startService(
this, path = path, action = "ACTION_PAUSE",
positionplus, ModelList[positionplus].filename
)
scaleDown.cancel()
binding.seekbartextend.text = createTimeLabel(mediaPlayer.duration)
binding.playButton.setImageResource(R.drawable.ic_baseline_play_arrow_24)
} else {
ForegroundService.startService(
this, path = path, action = "ACTION_PLAY",
positionplus,ModelList[positionplus].filename
)
binding.seekbartextend.text = createTimeLabel(mediaPlayer.duration)
mediaPlayer.setOnCompletionListener {
nextButton()
}
binding.playButton.setImageResource(R.drawable.circledpause)
runnable = Runnable {
binding.seekBar.max = mediaPlayer.duration
binding.seekBar.progress = mediaPlayer.currentPosition
binding.seekbarTextstart.text = createTimeLabel(mediaPlayer.currentPosition)
binding.seekbartextend.text = createTimeLabel(mediaPlayer.duration)
handler.postDelayed(runnable, 1000)
}
handler.post(runnable)
}
} else {
ForegroundService.startService(
this, path = path, action = "ACTION_RESET",
positionplus,ModelList[positionplus].filename
)
if (positionplus != position)
scaleDown = ObjectAnimator.ofPropertyValuesHolder(
view.image,
PropertyValuesHolder.ofFloat("scaleX", 1.1f),
PropertyValuesHolder.ofFloat("scaleY", 1.1f),
)
scaleDown.duration = 500
scaleDown.repeatCount = ObjectAnimator.INFINITE
scaleDown.repeatMode = ObjectAnimator.REVERSE
scaleDown.start()
binding.seekbartextend.text = createTimeLabel(mediaPlayer.duration)
mediaPlayer.setOnCompletionListener {
nextButton()
}
binding.playButton.setImageResource(R.drawable.circledpause)
runnable = Runnable {
binding.seekBar.max = mediaPlayer.duration
binding.seekBar.progress = mediaPlayer.currentPosition
binding.seekbarTextstart.text = createTimeLabel(mediaPlayer.currentPosition)
binding.seekbartextend.text = createTimeLabel(mediaPlayer.duration)
handler.postDelayed(runnable, 1000)
}
handler.post(runnable)
}
}
Related
Hello I am doing a little app for my homework and I want to display data from my php api on the app. But the Recycler View send this message 2022-04-25 00:41:36.662 13593-13593/net.robcorp.finalapp E/RecyclerView: No adapter attached; skipping layout before the adapter code runs because this message 2022-04-25 00:41:36.907 13593-13593/net.robcorp.finalapp I/System.out: [Drivers(pos=1, name=Charles Leclerc, nb=16, points=71, title=Ferrari), Drivers(pos=2, name=Esteban Ocon, nb=31, points=20, title=Alpine)] is displayed after the previous one and is suppose to run just before the adapter.
Here is the DriversFragment.kt:
package net.robcorp.finalapp
import android.content.Context
import android.graphics.Insets.add
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.OneShotPreDrawListener.add
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import net.robcorp.finalapp.R
import net.robcorp.finalapp.databinding.FragmentDriversBinding
import net.robcorp.finalapp.drivers.DriverFragmentAdapter
import net.robcorp.finalapp.drivers.Drivers
import org.json.JSONArray
class DriversFragment : Fragment(R.layout.fragment_drivers) {
private lateinit var recyclerView: RecyclerView
private lateinit var myAdapter: DriverFragmentAdapter;
lateinit var binding: FragmentDriversBinding
private val drivers = ArrayList<Drivers>()
val url = "https://robcorp.net/f1api/getdrivers.php"
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentDriversBinding.inflate(layoutInflater)
recyclerView = binding.driversRecyclerView
recyclerView.layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
myAdapter = DriverFragmentAdapter(drivers)
recyclerView.adapter = myAdapter
println("adapter loaded")
downloadDrivers()
}
fun downloadDrivers() {
val task = Volley.newRequestQueue(this.context)
val request = StringRequest(Request.Method.GET, url, {
response ->
val data = response.toString()
val jArray = JSONArray(data)
// Log.e("Error",response.toString())
for (i in 0..jArray.length()-1) {
val json_data = jArray.getJSONObject(i)
// Log.e("Jobject",json_data.toString())
val pos = i+1
val name = json_data.getString("Name")
val nb = json_data.getString("NB")
val points = json_data.getString("Points")
val title = json_data.getString("Title")
val driver = Drivers(pos, name, nb, points, title)
drivers.add(driver)
}
println(drivers)
myAdapter.notifyDataSetChanged()
}, {
error ->
println(error)
})
task.add(request)
}
}
Here is the DriverFragmentAdapter.kt:
package net.robcorp.finalapp.drivers
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import net.robcorp.finalapp.R
import net.robcorp.finalapp.databinding.DriverListBinding
class DriverFragmentAdapter(private var driversList: List<Drivers>): RecyclerView.Adapter<DriverFragmentAdapter.MyViewHolder>() {
class MyViewHolder(val binding: DriverListBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(driver: Drivers) {
val context = itemView.context
val pos = itemView.findViewById<TextView>(R.id.driver_position)
val bar = itemView.findViewById<TextView>(R.id.driver_bar)
val name = itemView.findViewById<TextView>(R.id.driver_name)
val nb = itemView.findViewById<TextView>(R.id.driver_number)
val team = itemView.findViewById<TextView>(R.id.driver_team)
val points = itemView.findViewById<TextView>(R.id.driver_points)
pos.text = driver.pos.toString()
name.text = driver.name
nb.text = driver.nb
team.text = driver.title
points.text = driver.points
if (driver.title == "Ferrari") {
bar.background = ContextCompat.getDrawable(context, R.drawable.ferrari_bar)
} else if (driver.title == "Alpine") {
bar.background = ContextCompat.getDrawable(context, R.drawable.alpine_bar)
} else if (driver.title == "Red Bull") {
bar.background = ContextCompat.getDrawable(context, R.drawable.redbull_bar)
} else if (driver.title == "Mercedes") {
bar.background = ContextCompat.getDrawable(context, R.drawable.mercedes_bar)
} else if (driver.title == "McLaren") {
bar.background = ContextCompat.getDrawable(context, R.drawable.mclaren_bar)
} else if (driver.title == "Alfa Romeo") {
bar.background = ContextCompat.getDrawable(context, R.drawable.alfaromeo_bar)
} else if (driver.title == "AlphaTauri") {
bar.background = ContextCompat.getDrawable(context, R.drawable.alphatauri_bar)
} else if (driver.title == "Williams") {
bar.background = ContextCompat.getDrawable(context, R.drawable.williams_bar)
} else if (driver.title == "Aston Martin") {
bar.background = ContextCompat.getDrawable(context, R.drawable.astonmartin_bar)
} else if (driver.title == "Haas") {
bar.background = ContextCompat.getDrawable(context, R.drawable.haas_bar)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(DriverListBinding.inflate(LayoutInflater.from(parent.context)))
}
override fun getItemCount(): Int {
return driversList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val driver = driversList[position]
holder.binding.apply {
println("je suis dans le binding")
holder.bind(driver)
}
}
fun setDriversList(driversList: List<Drivers>) {
this.driversList = driversList
notifyDataSetChanged()
}
}
fragment_drivers.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">
<!-- TODO: Update blank fragment layout -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/primary"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginBottom="10dp">
<TextView
android:id="#+id/calendar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="30dp"
android:layout_marginBottom="20dp"
android:fontFamily="#font/marianneb"
android:text="Pilotes"
android:textAlignment="center"
android:textColor="#color/white"
android:textSize="25sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/drivers_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toBottomOf="#+id/header"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
driver_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:elevation="8dp"
android:orientation="horizontal"
android:padding="10dp"
android:background="#drawable/rectangle">
<TextView
android:id="#+id/driver_position"
android:layout_width="30dp"
android:layout_height="match_parent"
android:fontFamily="#font/marianneb"
android:text="1"
android:textColor="#color/black"
android:textSize="25sp"
android:textAlignment="center"/>
<ImageView
android:id="#+id/driver_bar"
android:layout_width="20px"
android:layout_height="match_parent"
android:background="#drawable/ferrari_bar"/>
<LinearLayout
android:layout_width="250dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/driver_name"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:fontFamily="#font/marianneb"
android:text="Charles Leclerc"
android:textColor="#color/black"
android:textSize="15sp"
android:layout_marginStart="10dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/driver_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="2.5dp"
android:fontFamily="#font/mariannem"
android:text="16"
android:textColor="#color/black"
android:textSize="10sp" />
<TextView
android:id="#+id/driver_team"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="2.5dp"
android:fontFamily="#font/mariannem"
android:text="Ferrari"
android:textColor="#color/black"
android:textSize="10sp" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="#+id/driver_points"
android:layout_width="50dp"
android:layout_height="match_parent"
android:fontFamily="#font/marianneb"
android:text="578"
android:textColor="#color/black"
android:textSize="25sp"/>
</LinearLayout>
It’s a harmless warning. Since your RecyclerView is already in the layout, it attempts to draw it the moment your view hierarchy becomes visible, sees that there is no adapter assigned, and so it just issues the warning and doesn’t draw it.
Perhaps it would be cleaner to create your adapter (with an empty list) and assign it immediately upon inflating the view, and just update its list when the data is ready.
By the way, it is incorrect to inflate your layout in onCreate. That should be done in onCreateView.
Edit:
Your code here is inflating the layout twice, once for the variable v, and once for the binding property. First of all, there's no reason to inflate it twice. Secondly, since you use v as the return value of onCreateView, anything you do to the views in the binding is pointless and has no effect on the views that are actually on screen.
val v = inflater.inflate(R.layout.fragment_drivers, container, false)
binding = FragmentDriversBinding.inflate(layoutInflater)
// ...
return v
You should only inflate the view once (using the binding) and return the binding's view:
// DELETE THIS LINE: val v = inflater.inflate(R.layout.fragment_drivers, container, false)
binding = FragmentDriversBinding.inflate(layoutInflater)
// ...
return binding.root
Also, it is more proper to set up your views in onViewCreated() instead of in onCreateView(). And if you do that, you actually can move inflation into the super-constructor call by passing the view ID to the Fragment constructor, and then instead of inflating your binding, you bind to the existing view. It would look like this:
class DriversFragment : Fragment(R.layout.fragment_drivers) {
private lateinit var recyclerView: RecyclerView
private lateinit var myAdapter: DriverFragmentAdapter;
lateinit var binding: FragmentDriversBinding
private val drivers = ArrayList<Drivers>()
val url = "https://robcorp.net/f1api/getdrivers.php"
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentDriversBinding.bind(view)
recyclerView = binding.driversRecyclerView
recyclerView.layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
myAdapter = DriverFragmentAdapter(drivers)
recyclerView.adapter = myAdapter
println("adapter loaded")
downloadDrivers()
}
//...
}
To add a little bit of clarity to #Tenfour04 's answer.
You can't remove this. They are telling you how to properly inflate it with viewbinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentDriversBinding.inflate(layoutInflater, container, false)
return binding.root
}
also a little side note:
You should destroy your binding like so to prevent memory leaks
override fun onDestroyView() {
super.onDestroyView()
binding = null
}
Now to the question.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//binding = FragmentDriversBinding.bind(view) this is not needed since its already been inflated
//recyclerView = binding.driversRecyclerView why keep recyclerview as another variable when you can access it with binding.driversRecyclerView?
binding.driversRecyclerView.layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
myAdapter = DriverFragmentAdapter(drivers)
binding.driversRecyclerView.adapter = myAdapter
println("adapter loaded")
downloadDrivers()
}
Finally the issue is most likely your layout.
Since everything is wrapped inside a linear layout, the constraint layouts position lines don't do anything.
I removed the useless linear layout.
Hopefully this fixes any issues.
sorry about the formatting btw just use CTRL + ALT + L to auto format it
<?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">
<LinearLayout
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/primary"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginBottom="10dp">
<TextView
android:id="#+id/calendar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="30dp"
android:layout_marginBottom="20dp"
android:fontFamily="#font/marianneb"
android:text="Pilotes"
android:textAlignment="center"
android:textColor="#color/white"
android:textSize="25sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/drivers_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toBottomOf="#+id/header"/>
</androidx.constraintlayout.widget.ConstraintLayout>
when I am trying to click on an element on the reycler view it creates a new intent in the fragment and calls a different Activity but when it starts the new activity from the intent it just doesnt display anything or the breakpoint at SecondaryActivity shows up
this code is running from a fragment on the main activity and the new activity isnt displaying any layout
fun loadImages(){
recyclerView!!.setHasFixedSize(true)
recyclerView!!.layoutManager = GridLayoutManager(this.activity,4)
try {
this.imageList = ImageGallery.GetImagesList(this.context as Context )
}
catch (ex:Exception)
{
println(ex.message)
}
try { galleryAdapter = GalleryAdapter(this.context as Context,imageList,
object : IPhotoInterface {
override fun onPhotoClick(stringPath: String):Unit {
//process picture on click
imageIntent = android.content.Intent(context,SecondaryActivity::class.java)
imageIntent.putExtra("image_file",File(stringPath))
try{
startActivity(imageIntent)//here throws and exception
}catch(except:Exception)
{
println(except.message)
}
}
})
recyclerView?.adapter = galleryAdapter
galleryNumberText?.text = "${imageList.size} images"
}
catch(ex:Exception)
{
println(ex.message)
}
}
secondary_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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">
<include layout="#layout/secondary_action_bar"></include>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/grey">
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/gearicon"
app:flow_verticalAlign="center"
tools:ignore="MissingConstraints">
</ImageView>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_width="407dp"
android:id="#+id/bottomNavBar"
android:layout_height="57dp"
android:layout_marginTop="32dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.461"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintVertical_bias="1.0"
android:background="#color/black"
app:menu="#menu/bottom_navigation_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.drawerlayout.widget.DrawerLayout>
SecondaryActivity
kt
class SecondaryActivity: AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
val i = intent
val myParcelableObject: File? =
i.getParcelableExtra<Parcelable>("image_file") as File?
}
}
I get a null pointer exception when doing this
i am trying to set the value of total in BindViewHolder to my amount textview in my cart activity.
is there any way i can the total value to the amount textview? Either from the bindViewHolder or from On Create function?
i have tried severval methods including setText and findviewbyId but none seems to work , i still get the error in the logcat either Null Pointer Exception or attempt to invoke virtual method on a null reference.......
var CartItems = ArrayList<CartItemsModel>()
val adapter = CartAdapter(CartItems)
cart_recyclerview.adapter = adapter
cart_recyclerview.layoutManager = LinearLayoutManager(this)
CoroutineScope(Dispatchers.IO).launch {
try {
val snapshotquery = Firebase.firestore.collection("Profiles").document("User").collection("Cart Items").get().await()
for (document in snapshotquery.documents) {
val cartitems = document.toObject<CartItemsModel>()
withContext(Dispatchers.Main){
CartItems.add(cartitems!!)
Toast.makeText(this#cart_activity, "Suu" ,Toast.LENGTH_SHORT).show()
adapter.notifyDataSetChanged()
}
}
}catch (e: Exception){
withContext(Dispatchers.Main){
Toast.makeText(this#cart_activity, e.message, Toast.LENGTH_SHORT).show()
}
}
}
class CartAdapter(
var cartitems : List<CartItemsModel>
): RecyclerView.Adapter<CartAdapter.CartViewHolder>(){
inner class CartViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.cart_recycler_ui, parent, false)
return CartViewHolder(view)
}
override fun getItemCount(): Int {
return cartitems.size
}
override fun onBindViewHolder(holder: CartViewHolder, position: Int) {
holder.itemView.apply {
name_of_item_in_cart.text = cartitems[position].Name
cart_item_price.text = "$"+cartitems[position].Price
cart_item_quantity.text = cartitems[position].Quantity+"X"
Glide.with(this).load(cartitems[position].Image.toString()).into(img_of_item_in_cart)
if (cartitems[position].Price !=null){
val a = cartitems[position].Price!!.toDouble()
val b = cartitems[position].Quantity!!.toDouble()
val total : Double = a * b
//total is the value I want to set to my cart activity's textview
}
}
}
}
class CartItemsModel {
var Name:String? =null
var Image:String?=null
var Price:String?=null
var Quantity:String?=null
constructor()
constructor(Name:String,Image:String,Price:String,Quantity:String) {
this.Name = Name
this.Image = Image
this.Price = Price
this.Quantity = Quantity
}
}
//My cart Activity
<?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=".cart_activity">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.15" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.05" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/artifika"
android:text="My Order"
android:textColor="#color/black"
android:textSize="30sp"
app:layout_constraintLeft_toLeftOf="#id/guideline10"
app:layout_constraintTop_toTopOf="#id/guideline9" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.90" />
<TextView
android:id="#+id/back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:fontFamily="#font/alegreya"
android:text="Shop"
android:textColor="#color/black"
android:textSize="18sp"
app:layout_constraintLeft_toLeftOf="#id/guideline10"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/cart_recyclerview"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="48dp"
app:layout_constraintBottom_toTopOf="#+id/textView4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/textView2" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.70" />
<TextView
android:id="#+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/artifika"
android:text="Total"
android:textColor="#color/black"
android:textSize="30sp"
app:layout_constraintLeft_toLeftOf="#id/guideline10"
app:layout_constraintTop_toBottomOf="#id/guideline12" />
<TextView
android:id="#+id/amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/artifika"
android:textColor="#color/black"
android:textSize="30sp"
app:layout_constraintRight_toLeftOf="#id/guideline11"
app:layout_constraintTop_toTopOf="#id/guideline12" />
<Button
android:id="#+id/checkout_button"
style="#style/Theme.Ambergris"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="#font/aref_ruqaa"
android:text="Checkout"
android:textAllCaps="false"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="#id/guideline13"
app:layout_constraintLeft_toLeftOf="#id/guideline10"
app:layout_constraintRight_toLeftOf="#id/guideline11"
app:layout_constraintTop_toBottomOf="#id/amount" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="1" />
</androidx.constraintlayout.widget.ConstraintLayout>
In CartAdapter pass amount textview as parameter like this
class CartAdapter(
var cartitems : List<CartItemsModel>, var txtAmount: TextView
): RecyclerView.Adapter<CartAdapter.CartViewHolder>(){........
and then set it in onBindViewHolder as below
txtAmount.text = total
and while attaching adapter to recycler in cart activity pass your textview id like
val adapter = CartAdapter(CartItems,amount)
you can pass context from cart activity to adapter class like-
val adapter = CartAdapter(context,CartItems)
create a function setAmount
fun setAmount(var total){
txtAmount.text = total
}
in adapter class you can receive it like
class CartAdapter(
var context: Context var cartitems : List<CartItemsModel>
): RecyclerView.Adapter<CartAdapter.CartViewHolder>(){........}
call the function in view holder
override fun onBindViewHolder(holder: CartViewHolder, position: Int) {
holder.itemView.apply {
if (cartitems[position].Price !=null){
val a = cartitems[position].Price!!.toDouble()
val b = cartitems[position].Quantity!!.toDouble()
val total : Double = a * b
(context as CartActivity).setAmount(total)
//total is the value will set to in cart activity's textview
}
The RecyclerView calling inside Alert Dialog, I have tried setting width MATCH_PARENT at run time in onCreateView in adapter class.
if (binding.root.getLayoutParams ().width == RecyclerView.LayoutParams.MATCH_PARENT)
binding.root.getLayoutParams ().width = parent.getWidth ()
Tried calling inside in onCreateView but leaving space vertically. I tried all possible combination which is present on SO but nothing is working.
private fun initDialog() {
if (mAlertDialog == null) {
val mBuilder = AlertDialog.Builder(this)
val view1 = layoutInflater.inflate(R.layout.select_itinerary_dialog, null, false)
val mRecyclerView = view1.findViewById<RecyclerView>(R.id.mRecyclerView)
mRecyclerView?.adapter = SelectItineraryAdapter(this#AddItineraryActivity)
val llm = LinearLayoutManager(this#AddItineraryActivity)
// llm.isAutoMeasureEnabled = false
mRecyclerView?.layoutManager = llm
//mRecyclerView?.layoutManager = LinearLayoutManager(this#AddItineraryActivity)
mCheckBoxSelectAll = view1.findViewById<CheckBox>(R.id.checkSelctAll)
mCheckBoxSelectAll?.setOnCheckedChangeListener { _, b ->
if (!fromBroadcastReceiver) {
for (item in mItinerarylistResponse?.data?.itinerary!!) {
item?.isSelected = b
}
mRecyclerView?.adapter!!.notifyDataSetChanged()
}
fromBroadcastReceiver = false
}
view1.findViewById<AppCompatButton>(R.id.clearItinerary).setOnClickListener {
mAlertDialog!!.dismiss()
}
view1.findViewById<AppCompatButton>(R.id.doneItinerary).setOnClickListener {
try {
for (item in mItinerarylistResponse?.data?.itinerary!!) {
viewContainer.visibility = View.VISIBLE
if (item!!.item == "Wake Up") {
if (item.isSelected) {
wakeUpTimeTV.visibility = View.VISIBLE
wakeUpTimeLay.visibility = View.VISIBLE
} else {
wakeUpTimeTV.visibility = View.GONE
wakeUpTimeLay.visibility = View.GONE }
}
}
} catch (e: Exception) {
}
mAlertDialog!!.dismiss()
}
mBuilder.setView(view1)
mAlertDialog = mBuilder.create()
mAlertDialog?.window?.setBackgroundDrawableResource(android.R.color.transparent)
// mAlertDialog?.setView(view1)
}
}
Adapter
class SelectItineraryAdapter(val contecx: AddItineraryActivity) : RecyclerView.Adapter<SelectItineraryAdapter.MyHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
val binding = DataBindingUtil.inflate<RowItemItinararyBinding>(LayoutInflater.from(contecx), R.layout.row_item_itinarary, parent, false)
// val v= LayoutInflater.from(contecx).inflate(LayoutInflater.from(contecx), R.layout.row_item_itinarary, parent, false)
/* if (binding.root.getLayoutParams ().width == RecyclerView.LayoutParams.MATCH_PARENT)
binding.root.getLayoutParams ().width = parent.getWidth ()*/
val dd = MyHolder(binding)
return dd
}
override fun getItemCount(): Int {
return mItinerarylistResponse?.data?.itinerary!!.size
}
#SuppressLint("ClickableViewAccessibility")
override fun onBindViewHolder(holder: MyHolder, position: Int) {
holder.v.itinararyname.text = mItinerarylistResponse?.data?.itinerary!![position]?.item
holder.v.markReadCheck.setOnCheckedChangeListener { _, isChecked ->
mItinerarylistResponse?.data?.itinerary!![position]!!.isSelected = isChecked
val receiverIntentDetail = Intent()
receiverIntentDetail.action = isitinerarySelected
holder.v.markReadCheck.context.sendBroadcast(receiverIntentDetail)
}
holder.v.detailLat.setOnTouchListener { view, motionEvent ->
when (motionEvent.action) {
MotionEvent.ACTION_DOWN -> {
com.socrpro.utils.error("ACTION_DOWN")
}
MotionEvent.ACTION_UP -> {
// if (itinerary[position].readStatus == 0) {
holder.v.markReadCheck.performClick()
// }
com.socrpro.utils.error("ACTION_UP")
}
MotionEvent.ACTION_MOVE -> {
com.socrpro.utils.error("ACTION_MOVE")
}
}
true
}
holder.v.markReadCheck.isChecked = mItinerarylistResponse?.data?.itinerary!![position]!!.isSelected
}
class MyHolder(val v: RowItemItinararyBinding) : RecyclerView.ViewHolder(v.root)
}
Row_item
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:id="#+id/detailLat" android:layout_width="match_parent" android:layout_height="wrap_content"
android:clickable="true" android:orientation="vertical">
<LinearLayout android:id="#+id/readornot" android:layout_width="match_parent"
android:layout_height="#dimen/_25sdp" android:background="#color/white"
android:gravity="center_vertical" android:orientation="horizontal"
android:paddingTop="#dimen/_5sdp" android:paddingBottom="#dimen/_5sdp">
<CheckBox android:id="#+id/markReadCheck" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:button="#drawable/custom_checkbox" android:layoutDirection="rtl"
android:text="" />
<TextView android:id="#+id/itinararyname" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_gravity="center_vertical"
android:layout_marginStart="#dimen/_2sdp" android:layout_marginEnd="#dimen/_5sdp"
android:layout_weight="1" android:singleLine="true"
android:text="dfgdgfdggfdg" android:textColor="#color/colorPrimary"
android:textSize="#dimen/_10sdp" />
</LinearLayout>
<View android:layout_width="match_parent" android:layout_height=".5dp"
android:layout_alignBottom="#+id/readornot" android:background="#color/linecolorcc" />
</RelativeLayout>
</layout>
Updated.. new option added..*
TL;DR
Replace your vertical LinearLayout (which surrounds the RecyclerView) with a RelativeLayout
Option1 (old answer)
Before surrounding the layout with ScrollView
After adding ScrollView as root
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/search"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/search"
android:orientation="vertical">
<!--Header-->
<LinearLayout
android:id="#+id/static_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/HeaderStyle"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</RelativeLayout>
</ScrollView>
</layout>
The downside of adding ScrollView is that it causes all the surrounded Views to be Scrolled! So try the next option..
Option2 (better one)
Actually, I was not satisfied with Option1 because the header of the table should not disappear when user scrolls down the RecyclerView! So i've tried to replaced the LinearLayout (which surrounds the RecyclerView) with a RelativeLayout and it get the job done..
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/search"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/search">
<!--Header-->
<LinearLayout
android:id="#+id/static_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignStart="#id/rv"
android:layout_alignEnd="#id/rv"
style="#style/HeaderStyle"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/static_header"/>
</RelativeLayout>
</RelativeLayout>
</layout>
I have this drawer which opens normally but the scrolling in it is very slow, and I don't know why knowing that the image it has on top of it is not HD image, and available in the 4 sizes, I've done various examples in Java and it was fine, I wonder if the issue is that I'm using Kotlin in the adapter.
I would appreciate any help.
The activity's layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:fitsSystemWindows="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/gradient_background"
android:orientation="vertical">
<include
android:id="#+id/top"
layout="#layout/top_bar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize" />
<TextView
android:layout_below="#+id/top"
android:id="#+id/tvTradesTicker"
android:layout_width="match_parent"
android:layout_height="#dimen/trades_ticker_height"
android:background="#color/colorPrimaryLight"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:focusable="true"
android:freezesText="true"
android:marqueeRepeatLimit="marquee_forever"
android:padding="#dimen/small_margin"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="#color/darkGray"
android:textSize="#dimen/font"
android:visibility="visible" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rvGrid"
android:layout_below="#+id/tvTradesTicker"
android:layout_above="#+id/llFooter"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<include
layout="#layout/footer"
android:id="#+id/llFooter"
android:layout_width="match_parent"
android:layout_height="#dimen/footer_height"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/white"
android:fitsSystemWindows="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:paddingTop="#dimen/big_margin_padding"
android:orientation="vertical">
<include
layout="#layout/item_drawer_header"
android:id="#+id/header"
android:background="#color/white"
android:layout_width="match_parent"
android:layout_height="#dimen/drawer_header_height" />
<ListView
android:id="#+id/lvItems"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#color/white"
android:divider="#android:color/transparent"
android:paddingTop="#dimen/small_margin" />
</LinearLayout>
</android.support.design.widget.NavigationView>
The Drawer's Adapter:
class DrawerListAdapter : BaseAdapter {
private var drawerItems: MutableList<DrawerItem> = mutableListOf()
private var context: Context? = null
constructor(context: Context, notesList: MutableList<DrawerItem>) : super() {
this.drawerItems = notesList
this.context = context
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
val view: View?
val vh: ViewHolder
val inflater = LayoutInflater.from(context)
val type = getItemViewType(position)
if (convertView == null) {
view = if (type == 0){
inflater.inflate(R.layout.item_drawer_section, parent, false)
}else{
inflater.inflate(R.layout.item_drawer_child, parent, false)
}
vh = ViewHolder(view)
view.tag = vh
} else {
view = convertView
vh = view.tag as ViewHolder
}
val drawerItem = drawerItems[position]
vh.name.text = drawerItem.name
if (type == 0){
vh.rel.setBackgroundColor(ContextCompat.getColor(context!!, R.color.blue))
vh.name.setBackgroundColor(ContextCompat.getColor(context!!, R.color.colorAccent))
vh.name.setTextColor(ContextCompat.getColor(context!!, R.color.white))
}else if (type == 1){
vh.rel.setBackgroundColor(ContextCompat.getColor(context!!, R.color.white))
vh.name.setBackgroundColor(ContextCompat.getColor(context!!, R.color.white))
vh.name.setTextColor(ContextCompat.getColor(context!!, R.color.colorPrimary))
vh.separator.visibility = View.VISIBLE
}else{
vh.rel.setBackgroundColor(ContextCompat.getColor(context!!, R.color.white))
vh.name.setBackgroundColor(ContextCompat.getColor(context!!, R.color.white))
vh.name.setTextColor(ContextCompat.getColor(context!!, R.color.colorPrimary))
vh.separator.visibility = View.GONE
}
Actions.overrideFonts(context!!, vh.rel)
return view
}
override fun getItem(position: Int): DrawerItem {
return drawerItems[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getCount(): Int {
return drawerItems.size
}
override fun getItemViewType(position: Int): Int {
if (drawerItems[position].isHeader)
return 0
else if (!drawerItems[position].isLast)
return 1
else
return 2
}
override fun getViewTypeCount(): Int {
return 3
}
}
private class ViewHolder(view: View) {
val rel: RelativeLayout = view.findViewById(R.id.rel) as RelativeLayout
val name: TextView = view.findViewById(R.id.name) as TextView
val separator = view.findViewById<View>(R.id.separator)
}
What should I change, the activity layout, or the adapter or what i realy have no idea.
EDIT
I set the visibility of the marquee text view in the layout to gone, and everything worked just fine, does anybody know why? because I don't want to replace this text view with a horizontal recycler view
SOLVED.
Changed the approach completely, I stopped the marquee and applied cross fade animation to the text view, with a handler that changes the object being set in the text view at each iteration, and now it looks perfect and way more elegnat