Data binding: visible depend on list's size (via XML)? - android-databinding

Android Studio 3.1, java 1.8, Gradle 4.5.
Here my activity:
public class OrdersActivity extends AppCompatActivity {
ObservableArrayList<OrderEntry> orderList = new ObservableArrayList<>();
#Override
public void setOrderList(List<OrderEntry> list) {
this.orderList.clear();
this.orderList.addAll(list);
}
}
I want to show list's size in layout. So here layout's 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>
<import type="android.view.View" />
<variable
name="handler"
type="com.myproject.ui.OrdersActivity" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:visibility="#{handler.orderList.size > 0 ? View.VISIBLE : View.GONE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
</layout>
But I get error:
What went wrong:
Execution failed for task ':app:compileDebugJavaWithJavac'.
android.databinding.tool.util.LoggedErrorException: Found data binding errors.
****/ data binding error ****msg:Could not find accessor com.myproject.ui.OrdersActivity.orderList
file:\app\src\main\res\layout\orders.xml
loc:118:38 - 118:54
****\ data binding error ****

Did you try making it public or wrapping it with a public getOrderList()?

Related

Custom Toast inflater must be initialized

i have this fun
private fun testToast(){
val inflater:LayoutInflater
val view = inflater.inflate(R.layout.custom_toast_message)
val toast = Toast(this.context)
toast.setGravity(Gravity.TOP,0,70)
toast.duration = Toast.LENGTH_LONG
toast.view =view
toast.show()
}
the main idea its to change the background color of the toast without getting a square toast
in this code i get an error in inflater.inflate
(inflater must be initialized)
this is the test xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/custom_toast_container"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#color/background_blue"
android:padding="16dp"
android:weightSum="1"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_toasticon"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"/>
<TextView
android:id="#+id/TextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="14sp"
android:layout_gravity="center_vertical"
android:layout_weight="0.8"
android:textColor="#color/gauge_red"
android:fontFamily="#font/roboto"
android:text="Prueba prueba PRUEBA"
/>
</LinearLayout>
con someone help me or annother way to do a toast with custom color.
change the color of a toast with rounded corners
You declared the inflater variable but never assigned anything to it (using =). You can’t use a variable’s value if you haven’t assigned anything to it yet.
If this function is in an Activity, you can delete the line that declares val inflater and replace inflater. with layoutInflater. to use the property of the Activity. If it’s in a Fragment, use requireActivity().layoutInflator..
By the way, the latest version of Android has deprecated setting a custom view for your toast. On Android R and later if you set a view on your Toast, it won’t show. They want you to use SnackBars instead. There might be a third party library available that could help create something more similar to Toasts.
you can make a drawable resource to achieve it
toast_background.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#color/teal_200" />
<corners android:radius="48dp" />
</shape>
and use this drawable for background of toast view
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/custom_toast_container"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#drawable/toast_background"
android:orientation="horizontal"
android:padding="16dp"
android:weightSum="1">
<ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:src="#drawable/ic_launcher_background" />
<TextView
android:id="#+id/TextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="0.8"
android:text="Prueba prueba PRUEBA"
android:textColor="#color/purple_700"
android:textSize="14sp" />
</LinearLayout>
the result

Buttons don't work in new activity crated from service foreground window

I have a foreground Service with a button without any activities (initial was closed). When I click button the new activity window is created. The problem is that all buttons in new activity don't work
In foreground service I do:
override fun onClick(p0: View?) {
if (!moving) {
startActivity(Intent(applicationContext, Mmap_activity::class.java)
.setAction(Intent.ACTION_VIEW)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT))
}
}
In Manifest new activity declared:
<activity
android:name=".Mmap_activity"
android:exported="true"
android:theme="#style/ActionBarTheme">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
activity_mmap.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Mmap_activity">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/leftBorder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintGuide_percent=".80"
android:orientation="vertical" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/bottomBorder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".10" />
<ImageButton
android:id="#+id/mapexitButton"
style="#style/Widget.AppCompat.ImageButton"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#FFFFFF"
android:contentDescription="#string/Enter"
android:src="#drawable/ic_baseline_close_24"
app:layout_constraintBottom_toBottomOf="#id/bottomBorder"
app:layout_constraintLeft_toLeftOf="#id/leftBorder"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="SpeakableTextPresentCheck,DuplicateSpeakableTextCheck"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
Mmap_activity.kt:
class Mmap_activity : AppCompatActivity() {
private lateinit var binding: ActivityMmapBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_mmap)
binding = ActivityMmapBinding.inflate(layoutInflater)
binding.mapexitButton.setOnClickListener{
println("button pressed")
}
}
}
How to repair button in new activity? Why it doesn't work?
The error was here.
binding = ActivityMmapBinding.inflate(layoutInflater)
setContentView(binding.root)

Using navigation component Load fragment inside a fragment

In Home Fragment I am having xml as
<androidx.constraintlayout.widget.ConstraintLayout
android:background="#color/white"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#+id/bottomNavi"
app:navGraph="#navigation/bottm_navi" />
<meow.bottomnavigation.MeowBottomNavigation
android:id="#+id/bottomNavi"
app:mbn_circleColor="#color/white"
app:mbn_backgroundBottomColor="#color/app_dark_blue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
and my bottom navigation is
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="#+id/bottm_navi"
app:startDestination="#id/homeBottomOneFragment">
<fragment
android:id="#+id/homeBottomOneFragment"
android:name="com.krassier.customer.ui.home.bottom.HomeBottomOneFragment"
android:label="fragment_home_bottom_one"
tools:layout="#layout/fragment_home_bottom_one" />
<fragment
android:id="#+id/homeBottomTwoFragment"
android:name="com.krassier.customer.ui.home.bottom.HomeBottomTwoFragment"
android:label="fragment_home_bottom_two"
tools:layout="#layout/fragment_home_bottom_two" />
<fragment
android:id="#+id/homeBottomFourFragment"
android:name="com.krassier.customer.ui.home.bottom.HomeBottomFourFragment"
android:label="fragment_home_bottom_four"
tools:layout="#layout/fragment_home_bottom_four" />
<fragment
android:id="#+id/homeBottomThreeFragment"
android:name="com.krassier.customer.ui.home.bottom.HomeBottomThreeFragment"
android:label="fragment_home_bottom_three"
tools:layout="#layout/fragment_home_bottom_three" />
<fragment
android:id="#+id/homeFragment2"
android:name="com.krassier.customer.ui.home.HomeFragment"
android:label="HomeFragment" >
<action
android:id="#+id/action_homeFragment2_to_homeBottomOneFragment"
app:destination="#id/homeBottomOneFragment" />
<action
android:id="#+id/action_homeFragment2_to_homeBottomTwoFragment"
app:destination="#id/homeBottomTwoFragment" />
<action
android:id="#+id/action_homeFragment2_to_homeBottomThreeFragment"
app:destination="#id/homeBottomThreeFragment" />
<action
android:id="#+id/action_homeFragment2_to_homeBottomFourFragment"
app:destination="#id/homeBottomFourFragment" />
</fragment>
</navigation>
in homefragment I wrote
findNavController().navigate(R.id.action_homeFragment2_to_homeBottomOneFragment)
when I clicked on bottomnavigation I am trying to load another fragment in homefragment as bottom navigation is in home fragment, but error is:
java.lang.IllegalArgumentException: Navigation action/destination com.krassier.customer:id/action_homeFragment2_to_homeBottomOneFragment cannot be found from the current destination Destination(com.krassier.customer:id/homeFragment) label=fragment_home class=com.krassier.customer.ui.home.HomeFragment
At last I followed conventional way
private fun replaceFragment(fragment: Fragment) {
val fragmentManager = activity?.supportFragmentManager
val fragmentTransaction = fragmentManager?.beginTransaction()
fragmentTransaction?.replace(R.id.homeFragmentContainer, fragment)
fragmentTransaction?.commit()
}
Since you are in a fragment, you should try finding the navController this way.
val navHostFragment = supportFragmentManager.findFragmentById(R.id. fragment) as NavHostFragment. // the id of your FragmentContainerView
navController = navHostFragment.navController
You should take advantage of the NavigationUI library and let it handle the navigation fragment change logic for you
binding.bottomNavi.setupWithNavController(navController)
You can try this:
currentDestination?.getAction(direction.actionId)?.run { navigate(direction) }
}
fun NavController.safeNavigate(
#IdRes currentDestinationId: Int,
#IdRes id: Int,
args: Bundle? = null
) {
if (currentDestinationId == currentDestination?.id) {
navigate(id, args)
}
}
This crash occurs when you make multiple calls the navigate method.
https://nezspencer.medium.com/navigation-components-a-fix-for-navigation-action-cannot-be-found-in-the-current-destination-95b63e16152e
If you want to only just change the fragment like Fragment Transaction using Navigation component, you could do it like this:
private fun getNavController(): NavController {
val navController = findNavController(R.id.fragment)
return navController
}
private fun changeFragment(#IdRes viewId: Int) {
getNavController().popBackStack()
getNavController().navigate(viewId)
}
// how to use it
changeFragment(R.id.homeBottomFourFragment)

Is it possible to pass value to include layout without create variable only by xml?

Android Studio 3.1, Java 1.8.
I use data binding from Google.
Here my profile.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="handler"
type="com.myproject.ui.ProfileActivity" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/common_color_bg">
<include
android:id="#+id/prfoileToolbar"
layout="#layout/tool_bar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:title="#{#string/profile}" />
</android.support.constraint.ConstraintLayout>
</layout>
Here tool_bar.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="title"
type="String" />
</data>
<android.support.constraint.ConstraintLayout
android:id="#+id/toolBarConstraintLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolBar"
android:layout_width="0dp"
android:layout_height="#dimen/tool_bar_height"
android:background="#android:color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/toolbaTitleTextView"
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
android:textAllCaps="true"
android:textColor="#android:color/black"
android:textSize="13sp"
android:textStyle="bold"
android:text="#{title}"
app:layout_constraintBottom_toBottomOf="#+id/toolBar"
app:layout_constraintEnd_toEndOf="#+id/toolBar"
app:layout_constraintStart_toStartOf="#+id/toolBar"
app:layout_constraintTop_toTopOf="#+id/toolBar" />
</android.support.constraint.ConstraintLayout>
</layout>
And here my activity:
public class ProfileActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ProfileBinding binding = DataBindingUtil.setContentView(this, R.layout.profile);
binding.setHandler(this);
}
}
And it's work fine. In included xml (tool_bar) success show text "Profile". Nice.
I do this by create variabel "title" in tool_bar.xml
The question is:
Is it possible to pass string value to tool_bar.xml and set it to "toolbaTitleTextView" without create variable "title" ONLY by xml?

Using android DataBinding library how to pass parameters to binding events

I followed examples from Android Developers Binding Events and implementing step-by-step. That working fine. But I want to send parameters from adapter to handlers, how can achieve this using data binding handlers
I got the answer.
In xml for onclick use lambda expression
layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="movie"
type="embitel.com.databindingexample.helper.Movie" />
<variable
name="handler"
type="embitel.com.databindingexample.helper.MyHandlers" />
</data>
<android.support.v7.widget.CardView
android:id="#+id/cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="4dp"
android:onClick="#{(view)->handler.onItemClicked(view,movie)}"
app:cardBackgroundColor="#android:color/white"
app:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="128dp"
android:scaleType="centerCrop"
app:error="#{#drawable/ic_launcher}"
app:imageUrl="#{movie.imageUrl}" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#{movie.title}" />
</LinearLayout>
</android.support.v7.widget.CardView>
then create handler class as,
public class MyHandlers {
public void onItemClicked(View v, Movie movie) {
Context context = v.getContext();
context.startActivity(DetailActivity.buildIntent(context, movie));
}
}
then you need to set handler where that xml is iflated as,
binding.setHandler(new MyHandlers());
you can also put handler method in any class. In that case you have to set that class name as handler.