I'm trying to use View Binding in android, but the root's property (layout_gravity, layout_width) got ignored after build and installed,
it looks fine on design view (wrap_content and center_vertical).
i've enabled viewBinding in app gradle (android studio 3.6.1), and my root view group is a LinearLayout with some property
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical"
tools:context=".MainActivity">
...
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
}
and if i change layout_gravity to center or other value, it'll get unresolved reference: ActivityMainBinding in MainActivity
am i not supposed to use property on root layout?
so i switched to dataBinding instead of viewBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
}
}
<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">
<LinearLayout
...
Related
I am learning DataBinding in android studio. But I am facing a problem with binding a ModelView. I want to bind a function with a button on click event. I set a function in the model view. I want to update my text view with on click event of my button. But When I click the button my text is not updating. I can not understand what I have done wrong.
XML layout:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="model"
type="com.example.jetpack.MainModelView" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{model.title}"
android:textSize="28sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="Update Text"
android:onClick="#{()-> model.update()}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Main Model View:
class MainModelView : ViewModel() {
var title: String = " This is My Application"
fun update() {
title = "I am Changed"
Log.d("UPDATE", "update successfully from main model view")
}
}
Main Activity:
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
lateinit var mainModelView: MainModelView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
mainModelView = ViewModelProvider(this).get(MainModelView::class.java)
binding.model = mainModelView
}
}
My app Image:
thanks in advance for helping.
The title variable in ViewModel needs to be a ObservableField or LiveData otherwise you xml will never know when it's value got updated –
class MainViewModel : ViewModel() {
var text = MutableLiveData(" Welcome to my application ")
fun updateText() {
text.value = " Text is updated successfully "
}
}
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
// Creating MainViewModel object
mainViewModel = MainViewModel()
// Binding mainViewModel variable
// with MainViewModel object
binding.mainViewModel = mainViewModel
// passing LifeCycleOwner to binding object
binding.lifecycleOwner = this
}
}
I'm trying to get viewBinding to work.
This is the code:
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view: ConstraintLayout = binding.root
setContentView(view)
}
I manually declared the type ConstraintLayout because it's what I'm using for that activity called AskProfileImage:
<?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"
android:background="#303030"
tools:context=".AskProfileImage">
<ImageView
android:id="#+id/imageView97545"
android:layout_width="108dp"
android:layout_height="64dp"
android:layout_marginTop="8dp"
android:background="#00FFFFFF"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/logo2" />
But I'm getting the error
Type mismatch: inferred type is DrawerLayout but ConstraintLayout was expected
on
binding.root
how to fix this?
viewBinding creates a class for each activity. So in my case for this activity it's:
ActivityAskProfileImageBinding
So the correct code is:
private lateinit var binding: ActivityAskProfileImageBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAskProfileImageBinding.inflate(layoutInflater)
setContentView(binding.root)
}
Since viewBinding is probably broadly used now, I don't understand why the hell nobody could answer that and why google docs are as always useless
class
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(R.layout.activity_main)
}
layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity" />
</LinearLayout>
enter image description here
If you write ViewBinding and GoogleMap together, an error will occur. If you delete ViewBinding, no error will occur. What's the cause?
This is how you are supposed to do ViewBinding with an Activity:
private lateinit var binding: ResultProfileBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ResultProfileBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view) } ```
As you can see, the resource id of the layout is not used, but the view from the binding instead.
source: https://developer.android.com/topic/libraries/view-binding
And then how you set the SupportMapFragment into the xml:
<fragment
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Using class instead of android:name
source: https://developers.google.com/android/reference/com/google/android/gms/maps/SupportMapFragment
There is nothing wrong with having SupportMapFragment and ViewBinding together.
var viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(R.layout.activity_main)
should be
val viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
I've tried multiple solutions and read some other answers talking about the visibility of the class, but I've no added any private or protected modifier.
The point is, that I'm just have a very simple ViewBinding configuration, but it's showing the following message when I try to run it.
e: /app/src/main/java/com/adalpari/example/view/MainActivity.kt: (16,40): Cannot access '': it is private in 'ActivityMainBinding'
e: /app/src/main/java/com/adalpari/example/view/MainActivity.kt: (16,60): No value passed for parameter 'rootView'
e: /app/src/main/java/com/adalpari/example/view/MainActivity.kt: (16,60): No value passed for parameter 'progressBar'
e: /app/src/main/java/com/adalpari/example/view/MainActivity.kt: (16,60): No value passed for parameter 'storiesView'
The code, as you can see is pretty simple..
MainActivity:
#AndroidEntryPoint
class MainActivity : AppCompatActivity() {
val binding: ActivityMainBinding = ActivityMainBinding()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
onObserve()
}
...
}
xml file:
<?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=".view.MainActivity"
>
<com.adalpari.storiesview.view.StoriesView
android:id="#+id/stories_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<ProgressBar
android:id="#+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="#+id/stories_view"
app:layout_constraintEnd_toEndOf="#+id/stories_view"
app:layout_constraintStart_toStartOf="#+id/stories_view"
app:layout_constraintTop_toTopOf="#+id/stories_view"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
And finally the enabling of ViewBinding in app's gradle:
apply plugin: 'kotlin-kapt'
android {
...
buildFeatures {
viewBinding true
}
...
}
Any help is very appreciated, thanks in advance!
You're not supposed to use the constructors of data binding classes (they're private, as your error message says). Use the method ActivityMainBinding.inflate() to create your binding object
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
This is shown in the official docs for ViewBinding
I would recommend using dataBinding which includs viewBinding and other powerful features you may need in the future.
1. Enable dataBinding in Build Gradle File:
apply plugin: 'kotlin-kapt'
android {
...
buildFeatures {
dataBinding true
}
...
}
2. Wrap the Whole Layout inside <layout> Tag:
<layout //key point
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="#+id/xxx"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
...
</LinearLayout>
</layout>
3. Setup Activity/Fragment:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding //may need rebuild project
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
//binding.xxx.xxx
}
}
For Fragment:
binding: FragmentFirstBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_first, container, false)
I have a activity_main.xml file which looks like this.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
tools:context=".MainActivity"
android:id="#+id/main_linear_layout">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:layout_gravity="center_horizontal"
android:textSize="30sp"
android:id="#+id/dice_text"/>
<Button
android:id="#+id/roll_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/roll"/>
</LinearLayout>
So when i try to create a view binding and use it in Activity file,
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val root = binding.root
setContentView(root.main_linear_layout)
buttonClicked()
}
fun buttonClicked(): Unit {
val roll_button = binding.mainLinearLayout.roll_button
val text = binding.mainLinearLayout.dice_text
roll_button.setOnClickListener {
var randomNumber = Random().nextInt(6)+1
text.text = randomNumber.toString()
}
}
}
i have some issues. Naturally since the Linear Layout has layout_gravity set to center, it should be centered in the screen, both vertically and horizontally. This is the case in the design editor of the xml which is how it is supposed to be.
But when i run the app, in my phone both the text and button, aligns center_horizontal but not vertically.
I tried giving center_vertical also but doesn't work.
But if i don't use the view binding and use findViewById , it works fine.
Edit: I have removed the mainLinearLayout from the binding. So its just
setContentView(root)
I doesn't work.This is how i want it to be and this is how it is present in the Design View of the xml ( I have removed text and added Image)
But, when i run it, i get this. enter image description here
P.S I have just started learning android development
Adding
android:gravity = "center"
worked!!
Try this :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val root = binding.root
setContentView(root)
buttonClicked()
}
Source: https://developer.android.com/topic/libraries/view-binding#activities