Kotlin android Smart cast to 'BottomSheetBehavior app is crash - android

I do this :
private fun initComponent() {
// get the bottom sheet view
val llBottomSheet = findViewById<View>(R.id.bottom_sheet) as LinearLayout
// init the bottom sheet behavior
bottomSheetBehavior = BottomSheetBehavior.from(llBottomSheet)
// change the state of the bottom sheet
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED)
// set callback for changes
bottomSheetBehavior.setBottomSheetCallback(object : BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {}
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
})
}
And when I start my app is crash at line :
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED)
and this is a log :
Smart cast to 'BottomSheetBehavior<LinearLayout!>!' is impossible, because 'bottomSheetBehavior' is a mutable property that could have been changed by this time
And i do not have any idea what I should to repair this...
and this is xml file which I get in my project :
<?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"
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent"
android:orientation="vertical"
app:behavior_hideable="true"
app:behavior_peekHeight="250dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="5dp"
app:cardCornerRadius="1dp"
app:cardElevation="20dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/spacing_xxlarge"
android:layout_marginStart="#dimen/spacing_xxlarge"
android:gravity="center_vertical"
android:text="Dandelion Chocolate"
android:textAppearance="#style/TextAppearance.AppCompat.Headline" />
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
I try change a ConstraintLayout to LinearLayout but it do not help . Still my application is crash when I open it

In first step, you have to change root view (in your layout) from:
<androidx.constraintlayout.widget.ConstraintLayout
to:
<androidx.coordinatorlayout.widget.CoordinatorLayout
because BottomSheet needs CoordinatorLayout for it's behavior.
In the next step, you have to modify your layout:
move app:layout_behavior from root in to CardView
move app:id from root in to CardView
In the last step, modify casting of the layout from:
val llBottomSheet = findViewById<View>(R.id.bottom_sheet) as LinearLayout
to
val llBottomSheet = findViewById<CardView>(R.id.bottom_sheet)
In layout you have CardView, so casting as LinearLayout is not correct.
Full working example:
Code:
private fun initComponent() {
// get the bottom sheet view
val llBottomSheet = findViewById<CardView>(R.id.bottom_sheet)
// init the bottom sheet behavior
val bottomSheetBehavior = BottomSheetBehavior.from(llBottomSheet)
// change the state of the bottom sheet
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
// set callback for changes
bottomSheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {}
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
})
}
Layout:
<?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"
android:background="#android:color/transparent"
android:orientation="vertical"
app:behavior_hideable="true"
app:behavior_peekHeight="250dp">
<androidx.cardview.widget.CardView
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="5dp"
app:cardCornerRadius="1dp"
app:cardElevation="20dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:text="Dandelion Chocolate"
android:textAppearance="#style/TextAppearance.AppCompat.Headline" />
</androidx.cardview.widget.CardView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

You can use com.google.android.material.bottomsheet.BottomSheetBehavior only in a child of CoordinatorLayout.

Related

Getting DrawerLayout must be measured with MeasureSpec.EXACTLY when adding the drawer layout

I am trying to add drawerlayout in my fragment home. I am getting java.lang.IllegalArgumentException: DrawerLayout must be measured with MeasureSpec.EXACTLY. this error when I tried to attach drawer layout to my fragment.
I have root layout as constraint layout. Firstly I tried with root layout as drawerlayout still I wast getting this exception so I tried adding constraint layout to it but did not work.
It works when I give the hard coded value to height and width as 500dp.
But hard coded value cant be given as it will not be good practice for all devices size it will differ.
Below is my code
drawer layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
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">
<androidx.drawerlayout.widget.DrawerLayout
android:id="#+id/drawer"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/fragment_home"
android:visibility="visible" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:layout_gravity="start">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="#+id/nav_header"
layout="#layout/nav_header" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadeScrollbars="true"
android:scrollbars="none">
<include
android:id="#+id/menuItems"
layout="#layout/layout_navigation_menu" />
</ScrollView>
</LinearLayout>
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Home fragment layout
<?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">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:fillViewport="true"
android:fitsSystemWindows="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include android:id="#+id/app_bar"
layout="#layout/app_bar_main"/>
<RelativeLayout
android:id="#+id/relative_accept"
android:layout_width="match_parent"
android:layout_height="#dimen/margin_55"
android:orientation="horizontal"
android:background="#color/green_500"
app:layout_constraintTop_toBottomOf="#id/app_bar">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:textColor="#color/white"
android:layout_marginLeft="#dimen/margin_16"
android:layout_marginStart="#dimen/margin_16"
android:layout_marginRight="#dimen/margin_16"
android:layout_marginEnd="#dimen/margin_16"
android:text="#string/accepting_orders"
android:fontFamily="#font/roboto_regular"
android:textSize="#dimen/text_size_15"
android:layout_alignParentLeft="true"
android:layout_height="wrap_content" />
<Switch
android:id="#+id/switch1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:track="#drawable/switch_track_selector"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
tools:ignore="UseSwitchCompatOrMaterialXml" />
</RelativeLayout>
<FrameLayout
android:id="#+id/frameLayout_tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/relative_accept">
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="42dp"
android:layout_marginStart="#dimen/margin_16"
android:layout_marginLeft="#dimen/margin_16"
android:layout_marginTop="#dimen/margin_20"
android:layout_marginEnd="#dimen/margin_16"
android:layout_marginRight="#dimen/margin_16"
android:background="#drawable/grey_drawable"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:tabGravity="fill"
app:tabIndicatorHeight="0dp"
app:tabMode="fixed"
android:onClick="#{(v)->click.onClick(v)}"
app:tabBackground="#drawable/tab_selector"
app:tabSelectedTextColor="#color/white" />
</FrameLayout>
<androidx.viewpager.widget.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toBottomOf="#+id/frameLayout_tab" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
Home fragment
class HomeFragment : BaseFragment() , View.OnClickListener{
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.drawer_layout_navigation_view, container, false)
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
init()
controlInit()
}
override fun init() {
val toggle = ActionBarDrawerToggle(
(activity as MainActivity),
drawer,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close
)
drawer.addDrawerListener(toggle)
tabs.setupWithViewPager(view_pager)
bindViewPagerAdapter(view_pager, (activity as MainActivity))
bindViewPagerTabs(tabs, view_pager)
tabSettings()
}
private fun tabSettings() {
tabs.bringToFront()
view_pager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrolled(
position: Int, positionOffset: Float, positionOffsetP: Int
) {
}
override fun onPageSelected(position: Int) {}
override fun onPageScrollStateChanged(i: Int) {}
})
}
private fun bindViewPagerAdapter(view: ViewPager?, mainActivity: MainActivity) {
val adapter = OrdersAdapter(view?.context!!, childFragmentManager)
view.adapter = adapter
}
private fun bindViewPagerTabs(view: TabLayout, pagerView: ViewPager?) {
view.setupWithViewPager(pagerView, true)
}
private fun controlInit() {
imageView_drawer.setOnClickListener(this)
}
#SuppressLint("WrongConstant")
override fun onClick(p0: View) {
when (p0.id) {
R.id.imageView_drawer -> {
drawer.openDrawer(Gravity.START)
}
}
}
companion object {
#JvmStatic
fun newInstance() =
HomeFragment().apply {}
}
}
Please help with this.Thank you....
Your layout actually worked just fine when I tested it so I am not sure if the issue lies with the layout. However your layout files are overly complex, you don't really need any of the nested layouts that you have and can achieve the same results without. ConstraintLayout was developed with the purpose of simplifying layout hierarchies so you should be able to just use that to organise your child views.
Also the NavigationView component is meant to be used to display a menu from a menu resource, not just to be used as a wrapper for your own. Either choose to display your own menu completely or use their implementation as intended. There is some nice documentation for this on the [Material Design website] here.
So may I suggest you try to cut down on nesting your layouts and then see whether this incidentally fixes your problem.
The hierarchy that you might want would probably look something like this:
drawer_layout.xml
<DrawerLayout>
<include layout="#layout/home" />
<NavigationView />
</DrawerLayout>
home.xml
<ScrollView>
<ConstraintLayout>
<include layout="#layout/app_bar_main"/>
<TextView />
<Switch />
<TabLayout />
<ViewPager />
</ConstraintLayout>
</ScrollView>

Convert Bottom Sheet Card View to Top Sheet Card View

I was able to create a bottom sheet card view. I am trying convert what I haveto a top sheet card view(when user clicks button, card view should appear from the top, not bottom). Any assistance is appreciated.
SheetBehaviorActivity.kt
class SheetBehaviourActivity : AppCompatActivity() {
lateinit var sheetBehavior: BottomSheetBehavior<*>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val btn: Button = this.findViewById(R.id.testing_bottom_sheet_btn)
btn.setOnClickListener {
if (sheetBehavior.state != BottomSheetBehavior.STATE_EXPANDED) {
sheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
btn.text = "Close sheet"
} else {
sheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
btn.text = "Expand sheet"
}
}
val sheetContainer = findViewById<CardView>(R.id.bottom_sheet_container)
sheetBehavior = BottomSheetBehavior.from(sheetContainer)
sheetBehavior.isHideable = true
sheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}
}
activity_main.xml
<?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"
tools:context=".activities.SheetBehaviourActivity">
<Button
android:id="#+id/testing_bottom_sheet_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Expand Sheet" />
<android.support.v7.widget.CardView
android:id="#+id/bottom_sheet_container"
android:layout_width="match_parent"
app:cardCornerRadius="20dp"
app:cardBackgroundColor="#android:color/holo_blue_light"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
android:layout_height="300dp"/>
</android.support.design.widget.CoordinatorLayout>
This is TopSheetBehavior implementation topSheetLayout work fine in my case
Here is how you do it :
<?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"
tools:context=".activities.SheetBehaviourActivity">
<Button
android:id="#+id/testing_bottom_sheet_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Expand Sheet" />
<android.support.v7.widget.CardView
android:id="#+id/bottom_sheet_container"
android:layout_width="match_parent"
app:cardCornerRadius="20dp"
app:cardBackgroundColor="#android:color/holo_blue_light"
app:behavior_hideable="true"
app:behavior_peekHeight="56dp"
app:layout_behavior="your.package.components.TopSheetBehavior"/>
</android.support.design.widget.CoordinatorLayout>
This TopSheetBehavior is just replacing the behavior parameter

Card View Vertical

I am having significant difficulty in this and have tried everything imaginable. I am trying to make a card view draggable/swipeable vertically. All I want to accomplish is for the user to be able to swipe/drag the card view up and down. Please see attached photos-this is what I am trying to accomplish.
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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimary"
tools:context=".MainActivity">
<androidx.cardview.widget.CardView
android:id="#+id/cardviewbackground"
android:layout_width="match_parent"
android:layout_height="350dp"
android:layout_marginTop="-175dp"
app:cardBackgroundColor="#color/white"
app:cardCornerRadius="18dp"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</androidx.coordinatorlayout.widget.CoordinatorLayout>
MainActicity.kt
class MainActivity<T> : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
val listener = View.OnDragListener { view, event ->
when(event.action) {
DragEvent.ACTION_DRAG_STARTED -> {
event.clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)
}
else -> false
}
}
}

View below recyclerview is not clickable

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

How to retain state of views of orientation changes in Android Conductor?

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.

Categories

Resources