I am trying to define a custom view that extends a ViewPager.
First, I defined 2 xmls:
view_media_slider_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linearLayout"
android:layout_width="300dp"
android:layout_height="300dp"
android:orientation="vertical"
android:background="#color/colorAccent"
android:gravity="center">
<ImageView
android:id="#+id/image"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="#drawable/science"/>
<TextView
android:padding="16dp"
android:id="#+id/text"
android:textStyle="bold"
android:textSize="30sp"
android:text="Title Here"
android:textColor="#fff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
view_media_slider.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">
<androidx.viewpager.widget.ViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.viewpager.widget.ViewPager>
</LinearLayout>
Then, I defined an adapter that extends PagerAdapter, and I also hard-coded some data in the adapter.
class MediaSliderViewAdapter: PagerAdapter() {
private val TAG = MediaSliderViewAdapter::class.simpleName
private var mediaList = listOf(
Pair(1, "ha"),
Pair(2, "hsadfa"),
Pair(1, "hasad"),
Pair(1, "hasdaf"),
Pair(1, "haqw12"),
Pair(1, "hadsf"),
Pair(1, "ha23"),
Pair(1, "hadsaxc")
)
override fun isViewFromObject(view: View, `object`: Any): Boolean {
return view == `object`
}
override fun getCount(): Int {
Log.d(TAG, mediaList.size.toString())
return mediaList.size
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val inflater = (context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)) as LayoutInflater
val rootView = inflater.inflate(R.layout.view_media_slider_item, container, false)
rootView.findViewById<ImageView>(R.id.image).setImageResource(R.drawable.science)
rootView.findViewById<TextView>(R.id.text).text = mediaList[position].second
container.addView(rootView)
return rootView
}
fun setMediaData(mediaData: List<Pair<Int, String>>) {
mediaList = mediaData
notifyDataSetChanged()
}
Here is the custom view that I want to build, named MediaSliderView:
class MediaSliderView : ViewPager {
#JvmOverloads
constructor(
context: Context,
attrs: AttributeSet? = null
) : super(context, attrs)
private val viewPager: ViewPager
private val mediaSliderViewAdapter = MediaSliderViewAdapter()
init {
View.inflate(context, R.layout.view_media_slider, this) // inflate first before set below attrs, otherwise NPE
viewPager = findViewById(R.id.viewPager)
viewPager.adapter = mediaSliderViewAdapter
}
fun setMedia(urls: List<Pair<Int, String>>) {
mediaSliderViewAdapter.setMediaData(urls)
}
}
Finally, I put this custom view in a fragment named view_search.xml and the view pager does not show any data for some reason.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true">
<io.keyu.urekalite.view.MediaSliderView
android:background="#color/colorPrimary"
android:layout_width="500dp"
android:layout_height="500dp">
</io.keyu.urekalite.view.MediaSliderView>
</LinearLayout>
The data is already initialized in the adapter, so I think it should at least show something, but it does not.
You can create a class fragment for your view_media_slider_item.xml
and use the FragmentPagerAdapter instead of the PagerAdapter
viewPager.setAdapter(new FragmentPagerAdapter() {
#Override
Fragment getItem(position: Int) {
return //Fragment class of view_media_slider_item
}
#Override
int getCount() {
return 1
}
})
Related
I have layout in XML:
<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/hsv"
android:layout_width="match_parent"
android:layout_height="92dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#555555"
android:orientation="horizontal"
android:paddingHorizontal="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</HorizontalScrollView>
And extended HorizontalScrollView as custom view definition:
class TopBubblesWidget(context: Context, attrs: AttributeSet? = null) : HorizontalScrollView(context, attrs) {
private var binding: FragmentBiometricTopBubblesBinding = FragmentBiometricTopBubblesBinding.inflate(LayoutInflater.from(context))
private var data: List<BubblesWidget.Data>? = null
override fun onFinishInflate() {
super.onFinishInflate()
binding.rv.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
}
private fun initView(data: List<BubblesWidget.Data>) {
binding.rv.adapter = TopBubblesAdapter(data)
}
fun updateData(data: List<BubblesWidget.Data>) {
initView(data)
}
}
The problem is that TopBubblesWidget is not inflated by the XML and I do not see the RecyclerView.
What am I doing wrong here?
I have a feeling this is what you are looking for. This is a sample code -
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PartyViewHolder {
return PartyViewHolder(
PartyListItemBinding.inflate(LayoutInflater.from(parent.context)),
viewModel
)
}
and if you want to inflate a custom view like a prompt, here's a sample code -
private fun logOutAndExit() {
val dialogBox = Dialog(requireContext())
val promptLogOutBinding = PromptLogOutBinding.inflate(layoutInflater)//declaration done here
dialogBox.apply {
setContentView(promptLogOutBinding.root)
window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
setCancelable(false)
show()
}
in the top, my layout file is party_list_item while, in the bottom example, my layout is prompt_log_out
and this -
PartyListItemBinding.inflate(LayoutInflater.from(parent.context))
is how you inflate a custom layout
I have created a fragment and inside that fragment I have a recyclerview but when my fragment is loaded nothing shows and it give me this error "E/RecyclerView: No adapter attached; skipping layout". Below is the code for the adapter and fragment class, any help would be appreciated
Adapter Class:
class ViewAllRecipeAdapter(private val newList: ArrayList<Recipes>) :
RecyclerView.Adapter<ViewAllRecipeAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.view_all_recipe_item, parent, false)
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = newList[position]
holder.recipeName.text = currentItem.recipeName
holder.recipeDesc.text = currentItem.recipeDescription
}
override fun getItemCount(): Int {
return newList.size
}
class MyViewHolder(itemview: View) : RecyclerView.ViewHolder(itemview) {
val recipeName: TextView
val recipeDesc: TextView
init {
recipeName = itemView.findViewById<View>(R.id.recipe_name) as TextView
recipeDesc = itemView.findViewById<View>(R.id.recipe_description) as TextView
}
}
}
Fragment Class:
class ViewAllMyRecipesFragment : Fragment() {
private lateinit var recyclerview: RecyclerView
private lateinit var recipeData: ArrayList<Recipes>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view: View = inflater.inflate(R.layout.fragment_view_all_my_recipes, container, false)
recipeData = dummygenerator(10)
recyclerview = view.findViewById<RecyclerView>(R.id.recycler_view_all_recipes)
recyclerview.adapter = ViewAllRecipeAdapter(recipeData)
recyclerview.layoutManager = LinearLayoutManager(view.context)
recyclerview.setHasFixedSize(true)
// Inflate the layout for this fragment
return view
}
private fun dummygenerator(size: Int) : ArrayList<Recipes>{
val list = ArrayList<Recipes>()
for(i in 0 until size) {
val drawable = when (i % 3) {
0 -> "recipeName " +i
1 -> "recipeDescription " + i
else -> "Else " +i
}
val item = Recipes("title $i", "body")
list += item
}
return list
}
}
fragment_view_all_my_recipes.xml
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".ui.recipe.ViewAllMyRecipesFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view_all_recipes"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="#layout/view_all_recipe_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
view_all_recipe_item.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/recipe_image"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginEnd="331dp"
android:layout_marginBottom="651dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="#tools:sample/avatars" />
<TextView
android:id="#+id/recipe_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="25dp"
android:text="TextView"
android:textStyle="bold"
android:textSize="18sp"
app:layout_constraintStart_toEndOf="#+id/recipe_image"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/recipe_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="10dp"
android:text="TextView"
app:layout_constraintStart_toEndOf="#+id/recipe_image"
app:layout_constraintTop_toBottomOf="#+id/recipe_name" />
</androidx.constraintlayout.widget.ConstraintLayout>
Try moving all onCreateView logic to onViewCreated and
recyclerview.layoutManager = LinearLayoutManager(requireActivity())
recyclerview.adapter = ViewAllRecipeAdapter(recipeData)
because sometimes it causes problem when layoutManager is after adapter.
NewPaymentActivity
class NewPaymentActivity : AppCompatActivity(),SummaryFragment.OnFragmentInteractionListener{
override fun onFragmentInteraction(uri: Uri) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
internal lateinit var viewpageradapter: ViewPagerAdapter //Declare PagerAdapter
private var tabLayout: TabLayout? = null
var viewPager: ViewPager? = null
var toolbar: Toolbar? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_new_payment)
viewpageradapter= ViewPagerAdapter(supportFragmentManager)
viewPager = findViewById(R.id.viewPager) as ViewPager
setupViewPager(viewPager!!)
tabLayout = findViewById(R.id.tab_layout) as TabLayout
tabLayout!!.setupWithViewPager(viewPager)
tabLayout!!.setSelectedTabIndicatorColor(getResources().getColor(R.color.main));
val headerView = (getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
.inflate(R.layout.custom_tabs_for_payments, null, false)
val receiptDetails = headerView.findViewById(R.id.tb_receipt_details) as TextView
val paymentDetails = headerView.findViewById(R.id.tb_payment_details) as TextView
val invoiceDetails = headerView.findViewById(R.id.tb_invoice_details) as TextView
val summary = headerView.findViewById(R.id.tb_summary) as TextView
tabLayout!!.getTabAt(0)!!.setCustomView(receiptDetails)
tabLayout!!.getTabAt(1)!!.setCustomView(paymentDetails)
tabLayout!!.getTabAt(2)!!.setCustomView(invoiceDetails)
tabLayout!!.getTabAt(3)!!.setCustomView(summary)
}
private fun setupViewPager(viewPager: ViewPager) {
val adapter = ViewPagerAdapter(supportFragmentManager)
adapter.addFragment(ReceiptDetailsFragment(), "Receipt Details")
adapter.addFragment(PaymentDetailsFragment(), "Payment Details")
adapter.addFragment(InvoiceDetailsFragment(), "Invoice Details")
adapter.addFragment(SummaryFragment(), "Summary")
viewPager.adapter = adapter
}
internal inner class ViewPagerAdapter(manager: FragmentManager) : FragmentPagerAdapter(manager) {
private val mFragmentList = ArrayList<Fragment>()
private val mFragmentTitleList = ArrayList<String>()
override fun getItem(position: Int): Fragment {
return mFragmentList[position]
}
override fun getCount(): Int {
return mFragmentList.size
}
fun addFragment(fragment: Fragment, title: String) {
mFragmentList.add(fragment)
mFragmentTitleList.add(title)
}
override fun getPageTitle(position: Int): CharSequence {
return mFragmentTitleList[position]
}
}
}
custom_tabs_for_payment.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:gravity="top"
android:layout_margin="#dimen/dimen_6dp"
android:background="#color/row_gray"
android:orientation="horizontal">
<TextView
android:id="#+id/tb_receipt_details"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/left_tab"
android:gravity="center"
android:paddingBottom="#dimen/dimen_10dp"
android:paddingStart="#dimen/dimen_6dp"
android:paddingTop="#dimen/dimen_10dp"
android:text="Receip tDetails"
android:textColor="#color/main"
android:textSize="#dimen/text_dimen_8sp" />
<TextView
android:id="#+id/tb_payment_details"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/first_middle_tab"
android:layout_weight="1"
android:gravity="center"
android:paddingBottom="#dimen/dimen_10dp"
android:paddingStart="#dimen/dimen_6dp"
android:paddingTop="#dimen/dimen_10dp"
android:text="Payment Details"
android:textColor="#color/main"
android:textSize="#dimen/text_dimen_8sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/tb_invoice_details"
android:layout_weight="1"
android:background="#drawable/second_middle_tab"
android:gravity="center"
android:paddingBottom="#dimen/dimen_10dp"
android:paddingStart="#dimen/dimen_6dp"
android:paddingTop="#dimen/dimen_10dp"
android:text="Invoice Details"
android:textColor="#color/main"
android:textSize="#dimen/text_dimen_8sp" />
<TextView
android:id="#+id/tb_summary"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/right_tab"
android:gravity="center"
android:paddingBottom="#dimen/dimen_10dp"
android:paddingRight="#dimen/dimen_6dp"
android:paddingStart="#dimen/dimen_6dp"
android:paddingTop="#dimen/dimen_10dp"
android:text="Summary"
android:textColor="#color/main"
android:textSize="#dimen/text_dimen_8sp" />
</LinearLayout>
I need to change my current tab layout text views according to selections.There is a way to chnage the selected tab color but I need to access custom view and chnage the text colors and text background .Below I have added current screen.I'm new to Kotlin.Thanks in advanced.
You can use selector color for your text view like this
tab_text_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/text_selected" android:state_selected="true" /> // selected color
<item android:color="#ababab" /> // default color
</selector>
and then set to your textview
<TextView
android:id="#+id/tb_receipt_details"
android:layout_width="match_parent"
android:layout_height="match_parent"
...
android:textColor="#color/tab_text_color"/>
tabLayout!!.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
receiptDetails.setTextColor(resources.getColor(R.color.white))
val drawable = receiptDetails.getBackground() as GradientDrawable
drawable.setColor(resources.getColor(R.color.received_payments))
}
override fun onTabUnselected(tab:TabLayout.Tab?){
}
override fun onTabReselected(tab:TabLayout.Tab?) {
}
})
we can select tab using the above code and change any property from the selected tab.
I got a problem that I'm trying to solve lately, but I just can't find a solution.
In my project I got a fragment that inflates a layout, which has a viewPager. Until here everything is ok, but when I run the project to see it in my smartphone, everything show up but the viewpager. Am I missing something that I have to reconsiderate? This is what I got of my viewpager on the respective fragment in the onCreateView method:
viewPager = conteudo_feridas.findViewById<View>(R.id.viewPagerGaleria) as ViewPager
val adapter = ViewPageAdapter(activity!!.application)
viewPager.adapter = adapter
viewPager.currentItem = images.size
In my viewpager I got the following code:
class ViewPageAdapter(private val context: Context) : PagerAdapter(){
private var layoutInflater:LayoutInflater?= null
override fun isViewFromObject(view: View, `object`: Any): Boolean {
return view === `object`
}
override fun getCount(): Int {
return numeroFotos.size
return dias.size
return images.size
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
/**Set our vals to "inflate"**/
layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val v = layoutInflater!!.inflate(R.layout.custom_layout, null)
val nrFotos = v.findViewById<View>(R.id.dados_galeria_nr_fotos) as TextView
val dados = v.findViewById<View>(R.id.dados_galeria_data) as TextView
val image = v.findViewById<View>(R.id.image_view) as ImageView
vp.addView(v, 0)
return v
The layout of Viewpager, as well:
<android.support.constraint.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">
<android.support.v4.view.ViewPager
android:id="#+id/viewPagerGaleria"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="#id/pageIndicatorView">
</android.support.v4.view.ViewPager>
<com.rd.PageIndicatorView
android:id="#+id/pageIndicatorView"
android:layout_width="wrap_content"
app:layout_constraintBottom_toTopOf="#id/viewPagerGaleria"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:piv_padding="50dp"
app:piv_animationType="scale"
app:piv_viewPager="#id/viewPagerGaleria"
android:layout_height="wrap_content"
/>
I am suing viewpager for sliding images along with their text in android using kotlin. Despite having text in the layout and also adding the text to the view I am unable to view the text.
The layout code:
<?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="300dp"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ImageView
android:id="#+id/sliding_image"
android:layout_width="match_parent"
android:layout_height="270dp"
/>
<TextView
android:id="#+id/sliding_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#200"
android:layout_centerHorizontal="true"
android:layout_below="#+id/sliding_image"
android:gravity="center"
/>
</RelativeLayout>
The code snippet of the Adapter:
class SliderAdapter:PagerAdapter{
var context:Context
private var images:Array<Int>
private var texts:Array<Int>
lateinit var inflater: LayoutInflater
constructor(context: Context,images:Array<Int>,texts:Array<Int>):super(){
this.context=context
this.images=images
this.texts=texts
}
override fun isViewFromObject(view: View, `object`: Any): Boolean = view == `object` as RelativeLayout
override fun getCount(): Int = images.size
override fun instantiateItem(collection: ViewGroup, position: Int): Any {
var image:ImageView
var text:TextView
inflater=context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
var view = inflater.inflate(R.layout.splashscreenslider, collection,false)
image = view.findViewById(R.id.sliding_image)
image.setImageResource(images[position])
text = view.findViewById(R.id.sliding_text)
text?.text= texts[position].toString()
println("${text?.text}")
collection.addView(view)
return view
}
override fun destroyItem(collection: ViewGroup, position: Int, `object`: Any) {
collection.removeView(`object` as RelativeLayout)
}
}
By the way I'm not using fragments. I'm using only the views.
Any help is appreciated.
The answer to this question is modifying the layout file. This worked for me.
<?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="300dp"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ImageView
android:id="#+id/sliding_image"
android:layout_width="match_parent"
android:layout_height="240dp"
/>
<TextView
android:id="#+id/sliding_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:layout_marginTop="4dp"
android:textColor="#200"
android:layout_centerHorizontal="true"
android:layout_below="#+id/sliding_image"
android:gravity="center"
/>
</RelativeLayout>
The code snippet in the Adapter is given below.
class SliderAdapter:PagerAdapter{
var context:Context
private var images:Array<Int>
private var texts:Array<Int>
private lateinit var inflater: LayoutInflater
constructor(context: Context,images:Array<Int>,texts:Array<Int>):super(){
this.context=context
this.images=images
this.texts=texts
}
override fun isViewFromObject(view: View, `object`: Any): Boolean = view == `object` as RelativeLayout
override fun getCount(): Int = images.size
override fun instantiateItem(collection: ViewGroup, position: Int): Any {
var image:ImageView
var textview:TextView
inflater=context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
var view = inflater.inflate(R.layout.splashscreenslider, collection,false)
image = view.findViewById(R.id.sliding_image)
image.setImageResource(images[position])
textview = view.findViewById(R.id.sliding_text)
textview?.setText(texts[position])
println("${textview?.text}")
collection.addView(view)
return view
}
override fun destroyItem(collection: ViewGroup, position: Int, `object`: Any) {
collection.removeView(`object` as RelativeLayout)
}
}
Thank you Mike for responding.