简体   繁体   中英

Android App setContentView(R.layout.activity_main) vs View binding - layout_gravity not respected

I decided to finally jump into Kotlin this month as a hobby project. I'm working through a Udacity course (Android app dev with Kotlin).

I was just trying to replace the viewById with View binding (as a test for me). Which works fine.

But why if I use setContentView(view) from the binding does my layout no longer respect the gravity?

My layout file for my main activity is linear, with center-vertical layout_gravity

<<?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_vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1"
        android:textSize="30sp"
        android:layout_gravity="center_horizontal"/>

    <Button
        android:id="@+id/roll_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/roll"
        android:layout_gravity="center_horizontal"
        />

</LinearLayout>


When I use the old setContentView(R.layout.main_activity) in my activity, this displays as expected in the center of the screen

class MainActivity : AppCompatActivity() {
    @RequiresApi(Build.VERSION_CODES.P)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Let's do it the trad way without binding
        setContentView(R.layout.activity_main)
        val rollButton: Button = findViewById(R.id.roll_button)

Image with central gravity

If I swap this out for view binding instead and replace the setContentView as shown below

var binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

The app still runs, but now the text and button are at the top of the screen.

image top aligned

I was just testing that I could make this work in general, as I'd prefer to use in real life (anything to reduce nullPointer exceptions). But if I can't even get a simple example to work properly I'm stuffed.

Does anyone know what I am doing wrong? Or what concept I'm missing?

Try to change android:layout_gravity="center_horizontal" to android:layout_gravity="center" or maybe try to use RelativeLayout I heard that it's one of the best layouts.

I'm having trouble with this same problem. I was looking at the documentation for View Binding and it states:

"View binding doesn't support layout variables or layout expressions, so it can't be used to declare dynamic UI content straight from XML layout files."

I'm wondering if it's related to that? I'm still very new to this, but it's the only thing I can find so far that makes some sense to me.

UPDATE: Found another question asking the same thing ( How to use View Binding with Linear Layout? )

Changed android:layout_gravity="center_vertical" to android:gravity="center" , but then had an issue with the preview in Layout Editor not showing it centered; to remedy that I added tools:layout_gravity="center_vertical" so the activity_main.xml shows this now at the top:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    tools:layout_gravity="center_vertical"
    android:orientation="vertical"
    tools:context=".MainActivity">

Might not be the best solution, but works to show you the preview and then when you actually run it!

XML layout_ -prefixed attributes work with the parent view. When you inflate a view without a parent, the layout_* attributes have no effect.

An activity's setContentView(int) normally delegates to PhoneWindow#setContentView(int) that implicitly uses a parent container layout when inflating the XML layout. That's why the 1-arg inflation works in an activity.

View binding does not implicitly supply any parent layouts. You need to explicitly supply it with the three-arg inflate(int, View, boolean) method call where the first arg is the layout id, second one is the parent and the third controls whether the inflated layout should be added to the parent when inflating.

The usual an easy use case is to use fragments where the onCreateView() callback supplies you with a parent container layout and you can just return inflate(id, container, false) .

The PhoneWindow content layout is lazily generated, so you kinda have a chicken-and-egg problem. Calling setContentView() generates the content layout but when calling it you kinda want to already have inflated the view binding with a parent content layout.

My suggestion is to move the layout code away from your activity and instead use a fragment for it. Then you can use view binding in your fragment.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM