I trying to display a page feed or users post feed inside an app but I am not getting the desired output. Instead of post messages I get a blank activity and suspect the error is inside adapter class .
recylerView = findViewById<RecyclerView>(R.id.recyclerView)
var inBundle: Bundle = getIntent().getExtras()
var araayList: ArrayList<Data> = inBundle.getParcelableArrayList<Data>("data")
if (araayList == null) {
Toast.makeText(this, "it's empty", Toast.LENGTH_SHORT).show()
} else {
this.displayingPostAdapters = DisplayingPostAdapters(araayList, this)
this.displayingPostAdapters!!.notifyDataSetChanged()
var mlayoutManager = LinearLayoutManager(this)
this.recylerView?.layoutManager = mlayoutManager
this.recylerView?.itemAnimator = DefaultItemAnimator()
this.recylerView?.adapter = displayingPostAdapters
this.recylerView?.setHasFixedSize(true)
code inside Adapter class
package com.internshala.test1
import android.content.Context
import android.os.Build
import android.support.annotation.RequiresApi
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import org.json.JSONArray
class DisplayingPostAdapters(mAraay:ArrayList<Data>, context: Context) : RecyclerView.Adapter<DisplayingPostAdapters.myViewHolder>() {
var _mArray:ArrayList<Data>? = null
var mContext:Context? = null
init {
this._mArray = mAraay
this.mContext = context
}
#RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1) override fun onBindViewHolder(holder:myViewHolder?, position: Int) {
Toast.makeText(mContext, "NO DATA", Toast.LENGTH_SHORT).show()
var mDisplayingContent = _mArray?.get(position)
holder?.mDisplay?.text = mDisplayingContent?.message
holder?.mId?.text = mDisplayingContent?.created_time
holder?.mCreatedTime?.text = mDisplayingContent?.id
}
override fun getItemCount(): Int {
if (_mArray == null) {
return 0
} else {
return (_mArray as ArrayList<Data>).size
}
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int):myViewHolder {
var itemView = LayoutInflater.from(parent?.context)
.inflate(R.layout.row_custome_data, parent, false)
return myViewHolder(itemView)
}
class myViewHolder(view:View):RecyclerView.ViewHolder(view) {
var mDisplay:TextView? = null
var mId:TextView? = null
var mCreatedTime:TextView? = null
init {
this.mDisplay = view.findViewById(R.id.display)
this.mId = view.findViewById(R.id.mId)
this.mCreatedTime = view.findViewById(R.id.mCreatedDate)
}
}
}
When I try to run this app and click on post Button, my logcat issues this warning (Warning issued in logcat no crash):
https://i.stack.imgur.com/ZI1F8.png
My xml files look like this
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/recyclerView">
</android.support.v7.widget.RecyclerView>>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
Related
I am currently trying to make a custom to-do list app. I have a ListView element set up and a text field with a buttons to add/remove elements from the list. However, when I add elements, no text shows up. I know that the fields add and remove correctly, the only problem is that there is no text. (image for reference)
Here is my activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:visibility="visible"
tools:context=".MainActivity">
...
<ListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/textView1"
android:background="#color/white"
android:choiceMode="multipleChoice"
android:divider="#color/black"
android:textColor="#color/black" />
</RelativeLayout>
And here is all the Kotlin code:
package com.example.to_do
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.SparseBooleanArray
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.EditText
import android.widget.ListView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val itemlist = arrayListOf<String>()
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_multiple_choice, itemlist)
val add = findViewById<Button>(R.id.add)
val editText = findViewById<EditText>(R.id.editText)
val listView = findViewById<ListView>(R.id.listView)
val delete = findViewById<Button>(R.id.delete)
listView.adapter = adapter
add.setOnClickListener {
val todoitem = editText.text.toString()
if (todoitem.isEmpty() == false) {
itemlist.add(editText.text.toString())
adapter.notifyDataSetChanged()
}
editText.text.clear()
}
delete.setOnClickListener {
val position: SparseBooleanArray = listView.checkedItemPositions
val count = listView.count
var item = count - 1
while (item >= 0) {
if (position.get(item)) {
adapter.remove(itemlist[item])
}
item--
}
position.clear()
adapter.notifyDataSetChanged()
}
}
}
Can anybody help?
I'm new to android development in Kotlin. I would like to know how to implement a dynamic two column listView.
Here is what I am trying to achieve:
I should be able to dynamically add new elements by pressing the ADD button. The ADD button will open a dialog window where the user will fill out the info (description and price) of the new item.
The listView should look like this:
item price
item price
import android.os.Bundle
import android.view.View
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import com.example.recantoanimal.R
import kotlinx.android.synthetic.main.custom_dialog_fragment.*
class MainActivity : AppCompatActivity() {
private var list = mutableListOf<Model>()
private var adapter: ListViewAdapter? = null
private var addButton: Button? = null
var dialogDescription: TextView? = null
var dialogPrice: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var listView = findViewById<ListView>(R.id.listView)
addButton = findViewById<View>(R.id.addItem) as Button?
dialogDescription = findViewById(R.id.dialog_description)
dialogPrice = findViewById(R.id.dialog_price)
list.add(Model("rice", "10"))
list.add(Model("banana", "3"))
list.add(Model("apple", "2"))
listView.adapter = ListViewAdapter(this, R.layout.list_row, list)
addButton!!.setOnClickListener {
MyCustomDialog().show(supportFragmentManager, "MyCustomFragment")
list.add(Model(dialog_description.text.toString(), dialog_price.text.toString()))
listView.adapter = ListViewAdapter(this, R.layout.list_row, list)
adapter!!.notifyDataSetChanged()
}
}
}
class Model {
var description: String = ""
var price: String = ""
constructor(){}
constructor(description: String, price: String) {
this.description = description
this.price = price
}
}
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.TextView
import com.example.recantoanimal.R
class ListViewAdapter(var mCtx: Context, var resources: Int, var items: List<Model>): ArrayAdapter<Model>(mCtx, resources, items) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val layoutInflater: LayoutInflater = LayoutInflater.from(mCtx)
val view: View = layoutInflater.inflate(R.layout.list_row, null)
val descriptionTextView: TextView = view.findViewById(R.id.description)
val priceTextView: TextView = view.findViewById(R.id.price)
val mItem: Model = items[position]
descriptionTextView.text = mItem.description
priceTextView.text = mItem.price
return view
}
}
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.example.recantoanimal.R
class MyCustomDialog: DialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
getDialog()!!.getWindow()?.setBackgroundDrawableResource(R.drawable.round_corner);
return inflater.inflate(R.layout.custom_dialog_fragment, container, false)
}
override fun onStart() {
super.onStart()
val width = (resources.displayMetrics.widthPixels * 0.85).toInt()
val height = (resources.displayMetrics.heightPixels * 0.40).toInt()
dialog!!.window?.setLayout(width, ViewGroup.LayoutParams.WRAP_CONTENT)
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
tools:context=".activities.MainActivity"
>
<Button
android:id="#+id/addItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Add" />
<ListView
android:id = "#+id/listView"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:divider = "#null"
android:layout_below="#+id/addItem" />
</RelativeLayout>
I'm working on a project dealing with loading data from firebase into recyclerview. recyclerview seems working just fine but when i try to scroll it until the end of the posts it always make the app crash. it's so strange to me if i don't scroll to the end post it won't crash. in logcat it show only an error "fail to acquire dataanalyzer...". i have no clue about it. please kindly help!
Code as below :
package teacher
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.amazontutoringcenter.R
import com.example.amazontutoringcenter.databinding.ActivityTeacherLessonPlanBinding
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.*
import com.google.firebase.firestore.EventListener
import com.squareup.picasso.Picasso
import student.StudentPostData
import kotlin.collections.ArrayList
class TeacherLessonPlan: AppCompatActivity() {
private lateinit var binding : ActivityTeacherLessonPlanBinding
private lateinit var auth: FirebaseAuth
private lateinit var firebaseFirestore: FirebaseFirestore
private lateinit var userRecyclerview: RecyclerView
private lateinit var studentLessonPlanAdapter: LessonPlanAdapter
private lateinit var userArrayList: ArrayList<StudentPostData>
private lateinit var studentName: String
private lateinit var studentProfileUri : String
override fun onCreate(savedInstanceState: Bundle?){
super.onCreate(savedInstanceState)
binding = ActivityTeacherLessonPlanBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
auth = FirebaseAuth.getInstance()
// post lesson plan
binding.tvStudentName.setOnClickListener {
intent = Intent(this, TeacherLessonPlanPost::class.java)
intent.putExtra("studentName", studentName)
intent.putExtra("studentProfileUri", studentProfileUri)
startActivity(intent)
}
// get passing data to display profile and name
var b: Bundle = intent.extras!!
studentProfileUri = b.getString("studentProfileUri").toString()
studentName = b.getString("studentName").toString()
Picasso.get().load(studentProfileUri).fit()
.centerCrop().into(binding.imageStudentProfile)
userRecyclerview = findViewById(R.id.recyclerViewStudentLessonPlan)
userRecyclerview.layoutManager = LinearLayoutManager(this)
userArrayList = arrayListOf()
studentLessonPlanAdapter = LessonPlanAdapter(userArrayList)
userRecyclerview.adapter = studentLessonPlanAdapter
getStudentLessonPlanPost()
}
private fun getStudentLessonPlanPost() {
val uid = auth.currentUser!!.uid
firebaseFirestore = FirebaseFirestore.getInstance()
firebaseFirestore.collection("student").document("lesson plan")
.collection("$uid")
.addSnapshotListener(object : EventListener<QuerySnapshot> {
override fun onEvent(value: QuerySnapshot?, error: FirebaseFirestoreException?) {
if(error != null){
Log.d("check error", error.message.toString())
return
}
for(dc : DocumentChange in value?.documentChanges!!){
if(dc.type == DocumentChange.Type.ADDED){
userArrayList.add(dc.document.toObject(StudentPostData::class.java))
userArrayList.sortByDescending {
it.date
}
}
}
studentLessonPlanAdapter.notifyDataSetChanged()
}
})
}
inner class LessonPlanAdapter(private val userList : ArrayList<StudentPostData>) : RecyclerView.Adapter<LessonPlanAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(
R.layout.student_lesson_plan,
parent,false)
return MyViewHolder(itemView)
}
override fun getItemCount(): Int {
return userList.size
}
inner class MyViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){
val txLessonPlanDescription : TextView = itemView.findViewById(R.id.txLessonPlanDescription)
val imageStudentLessonPlan : ImageView = itemView.findViewById(R.id.imageStudentLessonPlan)
val imageStudentProfilePost : ImageView = itemView.findViewById(R.id.imageStudentProfilePost)
val tvStudentNamePost : TextView = itemView.findViewById(R.id.tvStudentNamePost)
// date on the post
val textDate : TextView = itemView.findViewById(R.id.txLessonPlanDate)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentitem = userList[position]
holder.txLessonPlanDescription.text = currentitem.description
holder.textDate.text = currentitem.date
Picasso.get().load(currentitem.imageUri)
.into(holder.imageStudentLessonPlan)
holder.tvStudentNamePost.text = studentName
Picasso.get().load(studentProfileUri).fit()
.centerCrop().into(holder.imageStudentProfilePost)
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<LinearLayout
android:id="#+id/relativeLayout"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="70dp"
android:padding="15dp"
android:elevation="10dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="5dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="#+id/imageStudentProfile"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="5dp"
android:layout_marginTop="50dp"
android:src="#drawable/ic_profile"
app:shapeAppearanceOverlay="#style/circular"
app:strokeColor="#0AF3D0"
android:layout_gravity="center_horizontal"
app:strokeWidth="1dp" />
<TextView
android:id="#+id/tvStudentName"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginLeft="10dp"
android:padding="5dp"
android:fontFamily="serif"
android:clickable="true"
android:hint="បង្ហោះកិច្ចតែងការបង្រៀន..."
android:background="#drawable/border_square"
android:textColor="#2196F3"
android:textSize="20dp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerViewStudentLessonPlan"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="#layout/student_lesson_plan">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
Since you are using the userArrayList variable globally to serve your adapter the data try to remove the LessonPlanAdapter class parameter and just use the global variable to populate it:
inner class LessonPlanAdapter() : RecyclerView.Adapter<LessonPlanAdapter.MyViewHolder>() {
...
override fun getItemCount(): Int = userArrayList.size
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentitem = userArrayList[position]
...
}
}
I think that the problem may be related to the fact that the class variable containing the data wasn't updated correctly.
That could have caused an index out of bounds exception when reaching the bottom of the list.
Solved ! I'm not sure what the problem was but I could solve it by deleting all of the documents that I have in firestore then trying to add new documents. now it's working fine. thank guys for your help !
I followed a tutorial to create an application that displays data from a mysql table, if i run the app everything works without error, the application opens with the header but without content, blank page instead of the content list.
activity_main.xml :
package com.example.bingmada
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
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 org.json.JSONArray
class MainActivity : AppCompatActivity() {
var adapter:ArticleAdapter ?=null
var articles:ArrayList<Article> ?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
articles= ArrayList()
getArticlesFromServer()
adapter = ArticleAdapter(articles!!)
var recyclerView = findViewById<RecyclerView>(R.id.recyclevirtuel)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter=adapter
}
fun getArticlesFromServer(){
var url="https://www.exemplesite.com/android/bingmada.php"
var stringRequest=StringRequest(Request.Method.GET,url,Response.Listener { response -> parseData(response) }, Response.ErrorListener { error ->
Toast.makeText(this,"Erreur de connexion ", Toast.LENGTH_SHORT).show()
})
var req=Volley.newRequestQueue(this)
req.add(stringRequest)
}
fun parseData(response:String){
var arrayJson = JSONArray(response)
for(i in 0..arrayJson.length()-1){
var currentObject=arrayJson.getJSONObject(i)
var article = Article(currentObject.getInt("id"),
currentObject.getString("nom"),
currentObject.getString("lienimg"),
currentObject.getString("ifram"))
articles?.add(article)
}
}
}
the page https://www.exemplesite.com/android/bingmada.php show :
[{"id":"1","nom":"tesmon","lienimg":"bingo1","ifram":"car1"},{"id":"2","nom":"testeds","lienimg":"bingo","ifram":"car2"},{"id":"3","nom":"test1","lienimg":"bingo3","ifram":"car3"},{"id":"4","nom":"testr","lienimg":"bingo4","ifram":"car4"},{"id":"5","nom":"test2","lienimg":"bingo5","ifram":"car5"},{"id":"6","nom":"letest","lienimg":"bingo6","ifram":"car6"},{"id":"7","nom":"test3","lienimg":"bingo7","ifram":"car7"},{"id":"8","nom":"testo","lienimg":"bingo8","ifram":"car8"},{"id":"9","nom":"test4","lienimg":"bingo9","ifram":"car9"},{"id":"10","nom":"testad","lienimg":"bingo10","ifram":"car10"},{"id":"11","nom":"test5","lienimg":"bingo11","ifram":"car11"},{"id":"12","nom":"testd","lienimg":"bingo12","ifram":"car12"},{"id":"13","nom":"test6","lienimg":"bingo13","ifram":"car13"},{"id":"14","nom":"testiu","lienimg":"bingo14","ifram":"car14"},{"id":"15","nom":"teste","lienimg":"bingo15","ifram":"car15"}]
in my page listevirtuelles.kt :
package com.example.bingmada
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class Article(var id:Int,var nom:String,var lienimg:String, var ifram:String){
}
class ArticleAdapter (var articles:ArrayList<Article>) : RecyclerView.Adapter<ArticleAdapter.MyViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
var vue=LayoutInflater.from(parent.context).inflate(R.layout.activity_listevirtuelles, parent, false)
return MyViewHolder(vue)
}
override fun getItemCount(): Int {
return articles.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
var article = articles.get(position)
holder.idvirtuelleli.setText(article.id)
holder.nomvisite.setText(article.nom)
holder.lieimgvisite.setText(article.lienimg)
holder.ifram.setText(article.ifram)
}
class MyViewHolder(var vue:View):RecyclerView.ViewHolder(vue){
var idvirtuelleli=vue.findViewById<TextView>(R.id.idvirtuelleli)
var nomvisite=vue.findViewById<TextView>(R.id.nom_virtuelleli)
var lieimgvisite=vue.findViewById<TextView>(R.id.lienimg)
var ifram=vue.findViewById<TextView>(R.id.ifram)
}
}
activity_main.xml page :
<?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:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclevirtuel"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
a page activity_listevirtuelles.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="#+id/idvirtuelleli"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="id"
android:textSize="25dp"
/>
<TextView
android:id="#+id/nom_virtuelleli"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Lenom"
android:textSize="25dp"
/>
<TextView
android:id="#+id/lienimg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="lien dimage"
android:textSize="25dp"
/>
<TextView
android:id="#+id/ifram"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="codeifram"
android:textSize="25dp"
/>
</LinearLayout>
can you help me find the problem please?
If you can see the relevant data in the activity. Since it is an asynchronous process, can you apply the structure I added to connect the data with recyclerview?
class MainActivity : AppCompatActivity() {
var adapter:ArticleAdapter ?=null
var articles:ArrayList<Article> ?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
articles= ArrayList()
adapter = ArticleAdapter(articles!!) // 1 line up to changed
getArticlesFromServer()
var recyclerView = findViewById<RecyclerView>(R.id.recyclevirtuel)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter=adapter
}
fun getArticlesFromServer(){
var url="https://www.exemplesite.com/android/bingmada.php"
var stringRequest=StringRequest(Request.Method.GET,url,Response.Listener { response -> parseData(response) }, Response.ErrorListener { error ->
Toast.makeText(this,"Erreur de connexion ", Toast.LENGTH_SHORT).show()
})
var req=Volley.newRequestQueue(this)
req.add(stringRequest)
}
fun parseData(response:String){
var arrayJson = JSONArray(response)
for(i in 0..arrayJson.length()-1){
var currentObject=arrayJson.getJSONObject(i)
var article = Article(currentObject.getInt("id"),
currentObject.getString("nom"),
currentObject.getString("lienimg"),
currentObject.getString("ifram"))
articles?.add(article)
}
adapter.notifydatasetchanged() // added
}
}
I have a plain basic recycler view and its adapter.In the single recycler view row, I got a textView which are floating numbers.The textView width length shall fixed in proportional sizes, i.e. 30 % of the screen.I want to put OnGlobalLayoutListener to auto resize text downward passively whenever the text exceed over the separator lineso that it fits in the textView box prepared.I don't want WRAP the numbers
So I add OnGlobalLayoutListener on each ViewHolder and expect to detect & tracing each row items if the costTextView is Overlapped to the separator line.
However what happened is it does not resize all rows, but part of items that exposed on user screen only. Example 4-7 does not affected, 8-12 is affected, so on.
MainFragment.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.elliot.financetracker.databinding.MainFragmentBinding
class MainFragment : Fragment() {
companion object {
private val TAG = "HomeFragment"
}
private lateinit var thisView: View
private lateinit var binding: MainFragmentBinding
private var cashList: ArrayList<Cash> = ArrayList()
private lateinit var recyclerView: RecyclerView
private lateinit var mAdapter: CashAdapter
init {
cashList = prepareMovieData()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding =
DataBindingUtil.inflate<MainFragmentBinding>(
inflater,
R.layout.main_fragment, container, false
)
thisView = binding.root
return thisView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView = binding.rvCash
mAdapter = CashAdapter(cashList, action)
val mLayoutManager: RecyclerView.LayoutManager = LinearLayoutManager(thisView.context)
recyclerView.layoutManager = mLayoutManager
recyclerView.itemAnimator = DefaultItemAnimator()
recyclerView.adapter = mAdapter
}
private val action = object : CashAdapter.ClickedListener {
override fun onItemClick(cash: Cash) {
val bundle = bundleOf("cash" to cash)
this#MainFragment.findNavController().navigate(R.id.edit_frag, bundle)
}
}
private val actionAddNewRecord = object : View.OnClickListener {
override fun onClick(v: View?) {
val arg = Bundle()
arg.putInt("sss", 43)
this#MainFragment.findNavController().navigate(R.id.edit_frag, arg)
}
}
private fun prepareMovieData(): ArrayList<Cash> {
for (i in 0..29) {
cashList.add(
Cash(
"-2000000000000000000000000.00",
"Action & Adventure $i"
)
)
}
return cashList
}
}
CashAdapter.kt
import android.graphics.Rect
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.elliot.financetracker.CashAdapter.CashViewHolder
import com.elliot.financetracker.databinding.CashListRowBinding
import com.elliot.financetracker.utils.*
//import com.example.recyclerviewbinding.databinding.MovieListRowBinding;
class CashAdapter(
private val cashList: List<Cash>,
private val clickedAction: ClickedListener
) : RecyclerView.Adapter<CashViewHolder>() {
companion object {
private var TAG = "CashAdapter"
}
inner class CashViewHolder(private val binding: CashListRowBinding) :
RecyclerView.ViewHolder(binding.root) {
var positionss: Int = -1
fun bind(cash: Cash, clickedAction: ClickedListener, positionss: Int) {
this.positionss = positionss
binding.cash = cash
binding.cvCashView.setOnClickListener {
clickedAction.onItemClick(binding.cash!!)
}
// ---------- NOTE HERE I ADD GLOBAL LAYOUT LISTENER ---------------------------------------------
this.binding.cvCashView.viewTreeObserver.addOnGlobalLayoutListener(globalObserver)
binding.executePendingBindings()
}
private val globalObserver = object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
val overlapped = isOverlapped(binding.tvItemCost, binding.separatorCost)
if (overlapped) {
Log.d(CashAdapter.TAG, "${CashAdapter.TAG}: isOverlapping : $positionss")
binding.tvItemCost.textSize = resizeTextDown(binding.tvItemCost)
// always assumed values in SP units
} else {
Log.d(CashAdapter.TAG, "${CashAdapter.TAG}: isNotOverlapping : $positionss")
}
}
}
private fun resizeTextDown(target: View): Float {
val t = target as TextView
val z = t.textSize
val a = z.pxToSp()
val b = a - 2.0F
// leave it as SP unit will do**
return b
}
}
interface ClickedListener {
fun onItemClick(cash: Cash)
}
fun isOverlapped(tvItemCost: View, g20: View): Boolean {
val firstPosition = IntArray(2)
val secondPosition = IntArray(2)
tvItemCost.getLocationOnScreen(firstPosition)
g20.getLocationOnScreen(secondPosition)
val rectFirstView = Rect(
firstPosition[0],
firstPosition[1],
firstPosition[0] + tvItemCost.measuredWidth,
firstPosition[1] + tvItemCost.measuredHeight
)
val rectSecondView = Rect(
secondPosition[0],
secondPosition[1],
secondPosition[0] + g20.measuredWidth,
secondPosition[1] + g20.measuredHeight
)
return rectFirstView.intersect(rectSecondView)
}
// plain basic recycler view adapter's methods
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CashViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = CashListRowBinding.inflate(layoutInflater, parent, false)
return CashViewHolder(binding)
}
override fun onBindViewHolder(holder: CashViewHolder, position: Int) {
val cash = cashList[position]
holder.bind(cash, clickedAction, position)
}
override fun getItemCount(): Int {
return cashList.size
}
}
cash_list_row.xml
<?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="cash"
type="com.elliot.financetracker.Cash" />
</data>
<androidx.cardview.widget.CardView
android:id="#+id/cv_cash_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
app:cardBackgroundColor="#color/colorLightGreen"
app:cardElevation="10dp"
app:cardCornerRadius="#dimen/default_card_corner_radius"
app:cardUseCompatPadding="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<TextView
android:id="#+id/tv_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="#{cash.description}"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#id/g_20"
app:layout_constraintTop_toBottomOf="#id/tv_date"
tools:text="Item description Item description Item description Item description" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/g_20"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.7"/>
<View
android:id="#+id/separator_cost"
android:layout_width="1dp"
android:layout_height="0dp"
android:padding="20dp"
android:background="#android:color/darker_gray"
app:layout_constraintLeft_toRightOf="#id/g_20"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="#+id/tv_item_cost"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="#{cash.amountString}"
android:gravity="center_vertical"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="RM -2000000000.00" />
<!-- removed out ...........-->
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</layout>
This can be perfectly solved by the auto resizing feature of TextView
use something like this
<TextView
android:layout_width="100dp"
android:layout_height="40dp"
android:maxLines="1"
android:text="hello world google"
app:autoSizeTextType="uniform"
app:autoSizeMinTextSize="1sp"
app:autoSizeMaxTextSize="25sp"
android:gravity="center_vertical"
/>