I would like to display either 4 textViews or just one editText depending on the data that I receive from back-end
Here is my view as below
<LinearLayout 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:orientation="vertical">
<LinearLayout
android:id="#+id/groupOfFour"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/first"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<TextView
android:id="#+id/second"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<TextView
android:id="#+id/third"
android:layout_width="match_parent"
android:layout_height="match_parent"
t/>
<TextView
android:id="#+id/fourth"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
<EditText
android:id="#+id/editText"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
In my fragment I am doing like this
class MyFragment : Fragment(R.layout.my_fragment) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val backedData = getRemoteData()
if(backedData.hasFour()) {
editText.visibility = Visibility.GONE
// set the four text view
} else {
groupOfFour.visibility = Visibility.GONE
}
}
}
Is there any other way of achieving the same behavior?
You can add the Views programmatically using addView
class MyFragment : Fragment(R.layout.my_fragment) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val backedData = getRemoteData()
if(backedData.hasFour()) {
groupOfFour.addView(addTextView("Textview 1"))
// set the four text view
} else {
groupOfFour.addView(addTextView("Textview 1"))
groupOfFour.addView(addTextView("Textview 2"))
groupOfFour.addView(addTextView("Textview 3"))
groupOfFour.addView(addTextView("Textview 4"))
}
}
fun addTextView(mytext: String):TextView {
return TextView(activity).apply {
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
text = mytext
}
}
}
And remove the TextViews from the layout
<LinearLayout 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:orientation="vertical">
<LinearLayout
android:id="#+id/groupOfFour"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
<EditText
android:id="#+id/editText"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
If you want to set static Ids to the TextViews, you can check this answer
Related
This is my recycler view items xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/recyclerItem"
app:cardElevation="10dp"
app:cardUseCompatPadding="false"
app:cardCornerRadius="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/recyclerItemImageView"
android:padding="8dp"
android:src="#mipmap/ic_launcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ImageView>
<TextView
android:id="#+id/recyclerItemTextView"
android:layout_marginStart="4dp"
android:textSize="18sp"
android:textColor="#color/black"
android:text="item"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
</androidx.cardview.widget.CardView>
And preview show me like this:
Preview
But emulator result this:
Emulator result
So items in recycler view does not match parent width on emulator. Other xml's there are:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragmentContainerView"
android:layout_margin="16dp"
android:name="com.example.databinding_practice.ListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/activityTextView"/>
<TextView
android:id="#+id/activityTextView"
android:layout_margin="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textColor="#color/black"
android:textSize="20sp" />
</RelativeLayout>
And fragment:
<?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=".ListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Adapter class and ListFragment like this:
RecyclerAdapter.kt:
class RecyclerAdapter(var recyclerItems: ArrayList<RecyclerItemModel>) : RecyclerView.Adapter<RecyclerAdapter.RecyclerViewHolder>() {
class RecyclerViewHolder(val binding: RecyclerItemBinding) : RecyclerView.ViewHolder(binding.root) {
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerViewHolder {
val binding = RecyclerItemBinding.inflate(LayoutInflater.from(parent.context))
return RecyclerViewHolder(binding)
}
override fun onBindViewHolder(holder: RecyclerViewHolder, position: Int) {
holder.binding.recyclerItemTextView.text = recyclerItems[position].text
recyclerItems[position].imageMipmapSource?.let { holder.binding.recyclerItemImageView.setImageResource(it) }
}
override fun getItemCount(): Int {
return recyclerItems.size
}
}
ListFragment.kt:
class ListFragment : Fragment() {
private var itemList : ArrayList<RecyclerItemModel> = arrayListOf()
private var recyclerAdapter: RecyclerAdapter = RecyclerAdapter(arrayListOf())
private lateinit var fragmentListBinding: FragmentListBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
fragmentListBinding = FragmentListBinding.inflate(layoutInflater)
return fragmentListBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
for (i in 0..3){
itemList.add(RecyclerItemModel(R.mipmap.ic_launcher,"Item $i"))
}
fragmentListBinding.recyclerView.layoutManager = LinearLayoutManager(context)
fragmentListBinding.recyclerView.adapter = recyclerAdapter
recyclerAdapter.recyclerItems = itemList
recyclerAdapter.notifyDataSetChanged()
}
Where am I doing wrong? If I replace match parent to fixed size like 200 dp - 300dp , thats working correctly but match parent does not. And why preview and emulator does not match ? Thank you.
In the fragment you should change layout_width and layout_height to "0dp" in your RecyclerView.
<?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=".ListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I am trying to make a bottom sheet with a recyclerview with cards. I was able to put the the cards within the bottom sheet but I am having problems with the recyclerview. As shown in the photo, it creates multiple bottom sheets with the cards within them. I have tried to fix this but so far have no luck. How can I make it so that the bottom sheet contains the cards with a recyclerview? I believe the problem is the Recyclerview in activity_main but don't know where to place it.
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (supportActionBar != null)
supportActionBar?.hide()
val modelList = readFromAsset()
val adapter = CustomAdapter(modelList, this)
rcv.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false) as RecyclerView.LayoutManager?
rcv.adapter = adapter;
configureBackdrop()
}
private var mBottomSheetBehavior: BottomSheetBehavior<View?>? = null
private fun configureBackdrop() {
// Get the fragment reference
val fragment = supportFragmentManager.findFragmentById(R.id.filter_fragment)
fragment?.let {
// Get the BottomSheetBehavior from the fragment view
BottomSheetBehavior.from(it.view)?.let { bsb ->
mBottomSheetBehavior = bsb
}
}
}
private fun readFromAsset(): List<Model> {
val modeList = mutableListOf<Model>()
val bufferReader = application.assets.open("android_version.json").bufferedReader()
val json_string = bufferReader.use {
it.readText()
}
val jsonArray = JSONArray(json_string);
for (i in 0..jsonArray.length() - 1) {
val jsonObject: JSONObject = jsonArray.getJSONObject(i)
val model = Model(jsonObject.getString("name"), jsonObject.getString("version"))
modeList.add(model)
}
return modeList
}
}
CustomAdapter.kt
class CustomAdapter(val modelList: List<Model>, val context: Context) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as ViewHolder).bind(modelList.get(position));
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return ViewHolder(layoutInflater.inflate(R.layout.backdrop_fragment, parent, false))
}
override fun getItemCount(): Int {
return modelList.size;
}
lateinit var mClickListener: ClickListener
fun setOnItemClickListener(aClickListener: ClickListener) {
mClickListener = aClickListener
}
interface ClickListener {
fun onClick(pos: Int, aView: View)
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
init {
itemView.setOnClickListener(this)
}
override fun onClick(p0: View?) {
mClickListener.onClick(adapterPosition, itemView)
}
fun bind(model: Model): Unit {
itemView.txt.text = model.name
itemView.sub_txt.text = model.version
val id = context.resources.getIdentifier(model.name.toLowerCase(), "drawable", context.packageName)
itemView.img.setBackgroundResource(id)
}
}
}
activity_main
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView"
android:text="#string/main_activity_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:id="#+id/rcv"/>
<fragment
app:behavior_hideable="false"
app:behavior_peekHeight="100dp"
android:layout_marginTop="?attr/actionBarSize"
app:behavior_skipCollapsed="false"
android:id="#+id/filter_fragment"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:name="behavior.sheet.bottom.BackdropFragment" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
backdrop_fragment
<?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"
android:background="#drawable/backdrop_fragment_background"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/backdrop_content" />
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="75dp"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:orientation="vertical"
card_view:cardCornerRadius="30dp"
card_view:cardElevation="5dp"
card_view:cardUseCompatPadding="false"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
card_view:contentPadding="10dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="#+id/txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:text="Title"
android:textSize="20sp"
android:textStyle="bold" />
<ImageView
android:id="#+id/img"
android:layout_width="30dp"
android:layout_height="match_parent"
android:layout_marginStart="25dp"
android:layout_toRightOf="#+id/txt"
android:contentDescription="#string/app_name" />
<TextView
android:id="#+id/sub_txt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="25dp"
android:layout_toRightOf="#+id/img"
android:autoSizeMaxTextSize="8sp"
android:autoSizeMinTextSize="6sp"
android:autoSizeStepGranularity="2sp"
android:autoSizeTextType="uniform"
android:text="Title" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
Please set the Bottom sheet Linear Layout to wrap-content
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/backdrop_fragment_background"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/backdrop_content" />
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="75dp"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:orientation="vertical"
card_view:cardCornerRadius="30dp"
card_view:cardElevation="5dp"
card_view:cardUseCompatPadding="false"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
card_view:contentPadding="10dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="#+id/txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:text="Title"
android:textSize="20sp"
android:textStyle="bold" />
<ImageView
android:id="#+id/img"
android:layout_width="30dp"
android:layout_height="match_parent"
android:layout_marginStart="25dp"
android:layout_toRightOf="#+id/txt"
android:contentDescription="#string/app_name" />
<TextView
android:id="#+id/sub_txt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="25dp"
android:layout_toRightOf="#+id/img"
android:autoSizeMaxTextSize="8sp"
android:autoSizeMinTextSize="6sp"
android:autoSizeStepGranularity="2sp"
android:autoSizeTextType="uniform"
android:text="Title" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
You have the RecyclerView in the activity_main layout file instead of inside the Fragment layout file.
Here is what you should do, create a class that inherits BottomSheetDialogFragment(). See below.
Add dependency implementation 'com.google.android.material:material:1.2.0-alpha04' inside the app/build.gradle.
Create your bottom sheet class
class BottomSheetExampleDialogFragment : BottomSheetDialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
) : View? =
inflater.inflate(R.layout.bottom_sheet_example_dialog_fragment, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Handle RecyclerView here
}
}
Bottom sheet layout file
<?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.recyclerview.widget.RecyclerView
android:id="#+id/rcv"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
Then in your MainActivity you can show the bottom sheet by using
val bottomSheetFragment = BottomSheetExampleDialogFragment()
bottomSheetFragment.show(supportFragmentManager, bottomSheetFragment.getTag())
Hi I am working on showing a view (publisher ad) below recycler view. Recycler view has some empty views to show publisher ad when it comes to related index. Currently I can click on any recycler view item and I am able to see my ad, but I cannot click on ad. How to achieve this? Here is my layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:ads="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical">
<com.google.android.gms.ads.doubleclick.PublisherAdView
android:id="#+id/ad_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:focusable="true"
android:focusableInTouchMode="true"
ads:adSize="SMART_BANNER"
ads:adUnitId="#string/parallax_ad_unit_id"/>
<widgets.AppSwipeRefreshLayout
android:id="#+id/swipe_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<widgets.AppRecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" />
</widgets.AppSwipeRefreshLayout>
</FrameLayout>
As you are using FrameLayout the PublisherAdView will be overlapped by AppRecyclerView or AppSwipeRefreshLayout, so when you click on item, that click event will be listened by `AppRecyclerView1 every time.
Try after changing the position of your RecyclerView and AdView
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:ads="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical">
<widgets.AppSwipeRefreshLayout
android:id="#+id/swipe_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<widgets.AppRecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" />
</widgets.AppSwipeRefreshLayout>
<com.google.android.gms.ads.doubleclick.PublisherAdView
android:id="#+id/ad_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:focusable="true"
android:focusableInTouchMode="true"
ads:adSize="SMART_BANNER"
ads:adUnitId="#string/parallax_ad_unit_id"/>
</FrameLayout>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical">
<widgets.AppSwipeRefreshLayout
android:id="#+id/swipe_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<widgets.AppRecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:nestedScrollingEnabled="false"
android:scrollbars="vertical"
ads:layout_constraintBottom_toBottomOf="parent"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintTop_toBottomOf="#id/ad_view" />
<com.google.android.gms.ads.doubleclick.PublisherAdView
android:id="#+id/ad_view"
android:layout_width="match_parent"
android:layout_height="0dp"
ads:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</widgets.AppSwipeRefreshLayout>
Use a RelativeLayout for activity_main.xml which allows to place views
on top of others (in Z axis).
ex: SwipeRefreshLayout is the top most view here.
<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:focusable="true"
tools:context=".MainActivity">
<View
android:id="#+id/ad"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorAccent" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="#+id/swipe_refresh_posts"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_posts"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</RelativeLayout>
Create two item layouts for two types of recycler view types
ex:
item_normal.xml, item_transparent.xml (where layout background is transparent that allow to see the layout below the surface area)
Setting android:clickable=false in item_transparent does not stop triggering the click event on transparent item, so use communication flow using interfaces, to bring the other view(ad) to the front when clicked on transparent item.
MainActivity.kt
class MainActivity : AppCompatActivity(), RvAdpater.OnItemClick {
private lateinit var swipeRefreshLayout: SwipeRefreshLayout
private lateinit var adView: View
private lateinit var rvPosts: RecyclerView
override fun onClick() {
bringAdFront()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupRecyclerView()
setupSwipeRefreshLayout()
}
private fun setupRecyclerView() {
rvPosts = findViewById(R.id.rv_posts)
rvPosts.layoutManager = LinearLayoutManager(this)
val rvAdpater = RvAdpater()
rvAdpater.setListener(this)
rvPosts.adapter = rvAdpater
}
private fun setupSwipeRefreshLayout() {
swipeRefreshLayout = findViewById(R.id.swipe_refresh_posts)
swipeRefreshLayout.setOnRefreshListener {
Log.d(TAG, "Refreshing...")
}
}
private fun bringAdFront() {
adView = findViewById<View>(R.id.ad)
adView.bringToFront()
}
// to go back to the normal recycler view(which is inside swipe refresh layout)
// when back button is pressed
override fun onBackPressed() {
val parent = swipeRefreshLayout.parent as ViewGroup
parent.removeAllViews()
parent.addView(adView, 0)
// at last add swipe refresh layout which is the container of the recyclerview
parent.addView(swipeRefreshLayout, 1)
}
}
RvAdapter.kt
const val TAG = "RvAdpater"
class RvAdpater : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private lateinit var listener:OnItemClick
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val viewNormal = LayoutInflater.from(parent.context).inflate(R.layout.item_normal, parent, false)
val viewTransparent = LayoutInflater.from(parent.context).inflate(R.layout.item_transparent, parent, false)
return when(viewType){
0 -> NormalViewHolder(viewNormal)
2 -> TransparentViewHolder(viewTransparent)
else -> NormalViewHolder(viewNormal)
}
}
override fun getItemCount(): Int = 10
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(getItemViewType(position)){
0 -> {
val normalHolder = holder as NormalViewHolder
normalHolder.tv.text = "Post"
normalHolder.itemView.setOnClickListener {
Log.d(TAG, "Clicked on Normal item")
}
}
2 -> {
val transparentHolder = holder as TransparentViewHolder
transparentHolder.itemView.setOnClickListener {
listener.onClick()
}
}
}
}
fun setListener(onItem:OnItemClick){
listener = onItem
}
interface OnItemClick{
fun onClick()
}
override fun getItemViewType(position: Int): Int = position % 2 * 2
class NormalViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val tv:TextView = itemView.findViewById(R.id.tv_post)
}
class TransparentViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
}
Checkout branch: with-swipe-layout
I have a simple structure. MainActivity with BottomNavigationView and NavController. In this nav controller, i have 4 items. One of them is FavoritesFragment. This fragment has simple layout:
<?xml version="1.0" encoding="utf-8"?>
<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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".view.main.favorites.FavoritesFragment">
<com.google.android.material.tabs.TabLayout
android:id="#+id/tlTest"
android:layout_width="match_parent"
android:layout_height="40dp"
app:layout_constraintTop_toTopOf="parent" />
<androidx.viewpager.widget.ViewPager
android:id="#+id/vpTest"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#id/tlTest"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
With following code:
FragmentAdapter
package com.lust.ahri.view.main.favorites
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
import com.lust.ahri.view.base.BaseFragment
class TestAdapter(fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
private val fragments: MutableList<BaseFragment> = mutableListOf()
private val titles: MutableList<String> = mutableListOf()
override fun getItem(position: Int): Fragment {
return fragments[position]
}
override fun getCount(): Int {
return fragments.count()
}
override fun getPageTitle(position: Int): CharSequence? {
return titles[position]
}
fun addFragment(fragment: BaseFragment, title: String) {
fragments.add(fragment)
titles.add(title)
}
}
And FavoritesFragment
class FavoritesFragment : BaseFragment() {
private lateinit var adapter: TestAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_favorites, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = TestAdapter(childFragmentManager)
adapter.addFragment(TestFragment(), "Test1")
adapter.addFragment(TestFragment(), "Test2")
vpTest.adapter = adapter
tlTest.setupWithViewPager(vpTest)
}
}
Problem that in my TestFragment i have layout:
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center|top">
<androidx.appcompat.widget.AppCompatEditText
android:id="#+id/test1"
android:layout_width="wrap_content"
android:hint="10"
android:maxLines="1"
android:maxLength="10"
android:layout_height="50dp" />
<EditText
android:layout_width="wrap_content"
android:hint="10"
android:maxLines="1"
android:maxLength="10"
android:layout_height="50dp"
android:layout_marginTop="70dp" />
</LinearLayout>
I meant that my edit texts will resize with wrap_content like as usual depending on the number of characters, in fact, the fields do not change their size but are only cropped.
I tried to change my layout to Constraint, Relative or another, but actually i couldn't find any solution.
I need an answer how to make edit texts change their width in a viewpager like a default layout behaviour and why it's happening.
I think the problem lies in the ViewPager 0dp height. Try this
<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.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/Widget.AppCompat.PopupMenu.Overflow" />
<android.support.design.widget.TabLayout
android:id="#+id/mtab_ID"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="#color/colorAccent1"
app:tabIndicatorHeight="3dp"
app:tabTextColor="#color/colorWhite"
/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/mViewpager_ID"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/app_bar"
/>
</RelativeLayout>
I am currently learning about the Conductor framework for Android and have a bit of a problem or misunderstanding of how it works.
I was under the impression that the method
setRetainViewMode(RetainViewMode.RETAIN_DETACH);
would save the states of the views in the controller. To test the behaviour, I added EditText views, entered a value in it and rotated the screen. I also added 2 views with onclick listeners attached, changing the background color onclick
The result of the test was that the EditText views maintained the state and preserved the entered values. But the 2 views, changed back to their original background color (none).
This is the behaviour of the views regardless on which RetainViewMode is set
I have this simple MainActivity (note: I'm writing in Kotlin):
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var router: Router = Conductor.attachRouter(this, controller_container, savedInstanceState)
if (!router.hasRootController()) {
var t : TestController = TestController()
t.retainViewMode = Controller.RetainViewMode.RETAIN_DETACH
router.setRoot(RouterTransaction.with(t))
}
}
companion object doTask {
fun start(activity : Activity) {
val intent = Intent(activity, MainActivity::class.java)
activity.startActivity(intent)
}
}
}
And here is the the TestController:
class TestController : BaseController() {
var i : Int = 0
var h : Int = 0
override fun onViewBound(view: View) {
view.a.setOnClickListener {
i++
if (i % 2 == 0) {
view.a.setBackgroundColor(ContextCompat.getColor(applicationContext, R.color.white))
} else {
view.a.setBackgroundColor(ContextCompat.getColor(applicationContext, R.color.turtle_green))
}
}
view.b.setOnClickListener {
h++
if (h % 2 == 0) {
view.b.setBackgroundColor(ContextCompat.getColor(applicationContext, R.color.white))
} else {
view.b.setBackgroundColor(ContextCompat.getColor(applicationContext, R.color.blue_light))
}
}
}
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
return inflater.inflate(R.layout.controller_layout_test, container, false)
}
}
And xml layout file controller_layout_test:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<requestFocus></requestFocus>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/logo_simple"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="300dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="30dp"
android:layout_gravity="center"
android:background="#color/transparent50p"
android:padding="20dp">
<EditText
android:id="#+id/gt"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:padding="6dp"
android:background="#color/white_transparent50p"/>
/>
<EditText
android:id="#+id/erergeargf"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:padding="6dp"
android:background="#color/white_transparent50p"/>
<View
android:id="#+id/a"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="5dp"
android:layout_gravity="center"></View>
<View
android:id="#+id/b"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="5dp"
android:layout_gravity="center"></View>
</LinearLayout>
</ScrollView>
</FrameLayout>
activity_main xml layout looks like this:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="dk.minreklame.minetilbud_v2.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
/>
</android.support.design.widget.AppBarLayout>
<com.bluelinelabs.conductor.ChangeHandlerFrameLayout
android:id="#+id/controller_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
</android.support.design.widget.CoordinatorLayout>
As your views have references to the host Activity, they will never be retained across orientation changes. That would cause a memory leak. The docs on RETAIN_DETACH state:
The Controller will retain its reference to its view when detached, but will still release the reference when a config change occurs.