Actual Code:
My Main Activity:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val rollButton = binding.rollButton
rollButton.setOnClickListener { rollDice() }
setContentView(binding.root)
}
private fun rollDice() {
val randomDiceRoll = Random.nextInt(6) + 1
Toast.makeText(this, randomDiceRoll.toString(), Toast.LENGTH_SHORT).show()
binding.resultText.text = randomDiceRoll.toString()
}
My XML file:
<?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:layout_gravity="center_vertical"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="#+id/result_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/count"
android:textSize="30sp" />
<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>
Preview in android studio:
Actual layout in device:
If I change setContentView(binding.root) to setContentView(R.layout.activity_main), the layout of Android Studio and the device become the same, but of course, the button doesn't work anymore...
Why does this happen? Why is ActivityMainBinding.inflate(layoutInflater) changing the layout? How to fix this?
Thanks
GitHub Repo:
https://github.com/Wizard28082006/Dice_Roller
If I change setContentView(binding.root) to setContentView(R.layout.activity_main), the layout of Android Studio and the device become the same
Most likely caused by how the container is not passed to the inflater if the view is inflated like this.
You could try the following instead:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
And
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.bind(findViewById(R.id.root))
val rollButton = binding.rollButton
rollButton.setOnClickListener { rollDice() }
Maybe you should set android:layout_height as match_parent in your linearlayout and align inner views in it.
Since the screenshots suggest that the question comes from the Udacity course on Andorid, there is a good explanation on the course knowledge hub (link accessible only to the course users). In short, the explanation is the two things mentioned in the setContentView docs and the ViewBinding docs.
First is that when using setContentView the
layout parameters of the specified view are ignored
and the drawback of ViewBinding is
it doesn't support layout variables or layout expressions, so it can't
be used to declare dynamic UI content straight from XML layout files
There is a difference between android:gravity and android:layout_gravity:
android:gravity sets the gravity of the View Content (or child in case it was applied on a ViewGroup).
meanwhile android:layout_gravity sets the gravity of the View it is applied on, relative to its parent.
<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:gravity="center_vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:layout_gravity="center_horizontal"
android:textSize="30sp"/>
</LinearLayout>
Adding android:gravity = "center" to LinearLayout solves the problem.
Related
I have an activity which I will show xml for below, containing a webView inside an appBarLayout. Now to be frank, I don't know where the appBarLayout came from because I dont remember adding it in. But anyways, the screen has stacked in the following order top->bottom: a textView, a videoView, and a webView. So the HTML being displayed in the webview is only maybe the bottom half of the screen. Below the xml snippet, I have a image of how this looks from the design POV. The closest I ever got to scrolling is if the webView and friends are NOT children of appBarLayout but then the webview takes up entire screen which is not desirable.
I admit, this probably is setup wrong but I will gladly take whatever advice you have and suggestions on editing the way this is arranged/configured.
Activity XML
<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"
tools:context=".Lesson">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:isScrollContainer="true"
android:scrollbars="vertical"
android:theme="#style/Theme.ProjectName.AppBarOverlay"
android:verticalScrollbarPosition="right">
<TextView
android:id="#+id/textView2"
android:layout_width="match_parent"
android:layout_height="64dp"
android:fontFamily="#font/reem_kufi"
android:gravity="center"
android:isScrollContainer="false"
android:linksClickable="true"
android:text="Title Goes Here"
android:textAlignment="center"
android:textColor="#FFFFFF"
android:textSize="24sp"
android:textStyle="bold" />
<com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
android:id="#+id/videoView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<WebView
android:id="#+id/lessonContentView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadeScrollbars="true"
android:isScrollContainer="true"
android:nestedScrollingEnabled="true"
android:overScrollMode="ifContentScrolls"
android:persistentDrawingCache="scrolling"
android:scrollbars="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
app:layout_scrollFlags="scroll" />
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Kotlin File
class Lesson : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityLessonBinding
private lateinit var webView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLessonBinding.inflate(layoutInflater)
setContentView(binding.root)
webView = findViewById(R.id.lessonContentView)
if(webView != null){
webView.requestFocus()
webView.settings.javaScriptEnabled = true
webView.isSoundEffectsEnabled = true
webView.isVerticalScrollBarEnabled = true
webView.settings.loadWithOverviewMode = true
webView.settings.allowContentAccess = true
webView.settings.domStorageEnabled = true
webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
if (url != null) {
view?.loadUrl(url)
}
return true
}
}
webView.loadUrl("file:///android_asset/lesson.html")
}
val youTubePlayerView: YouTubePlayerView? = findViewById(R.id.videoView)
if (youTubePlayerView != null) {
lifecycle.addObserver(youTubePlayerView)
}
youTubePlayerView?.addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
override fun onReady(youTubePlayer: YouTubePlayer) {
val videoId = "yJdkdiAly0w"
youTubePlayer.cueVideo(videoId, 0F)
}
})
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_content_lesson)
return navController.navigateUp(appBarConfiguration)
|| super.onSupportNavigateUp()
}
}
Component Tree & Design
How it looks now
How it looked when I got it to scroll but not how I wanted
I have already tried the advice given on several posts here on StackOverflow so please do not just mark as Duplicate and run off. Probably a quarter of the code in the project right now is from me trying to get scrolling to work with the advice of this site.
I have tried messing with all the scroll attributes for basically every view on here.
I have added StackOverflow recommended items such as the app:layout_behavior and these webview settings below:
webView.isVerticalScrollBarEnabled = true
webView.settings.loadWithOverviewMode = true
webView.settings.allowContentAccess = true
When I got it to scroll but wasnt correct, shown in image link earlier, I had removed all the views from the appBarLayout parent making everything a direct child of what this says is a "CoordinatorLayout".
Received help outside of SO (Discord) and I will go over the changes below.
First, I removed the appBarLayout. As originally mentioned, I wasn't even sure about it or how it got there as a parent of everything. I also removed ITS PARENT the coordinatorLayout by changing it to a constraintLayout. This is the parent of my 3 needed pieces (text, video, web) all stacked on top of each other. A few attributes were removed from the xml as well.
Please feel free to comment if you see this in the future and have questions about how I solved this.
<?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:id="#+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Lesson">
<com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
android:id="#+id/videoView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView2" />
<TextView
android:id="#+id/textView2"
android:layout_width="412dp"
android:layout_height="54dp"
android:fontFamily="#font/reem_kufi"
android:gravity="center"
android:isScrollContainer="false"
android:linksClickable="true"
android:text="Winds & Temperatures Aloft"
android:textAlignment="center"
android:textColor="#000000"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<WebView
android:id="#+id/lessonContentView"
android:layout_width="412dp"
android:layout_height="0dp"
android:fadeScrollbars="true"
android:scrollbars="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/videoView"
app:layout_constraintVertical_bias="0.483"
app:layout_scrollFlags="scroll" />
</androidx.constraintlayout.widget.ConstraintLayout>
So I was trying animation on Android using View Binding and it was not working, I tried the old way of getting views (findViewById()) and it happened to work just fine. Any answer to why View Binding doesn't work with animations? Thanks in advance for any answer.
Here the example code:
activity_main.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"
android:background="#drawable/sopint_background"
tools:context=".MainActivity">
<TextView
android:id="#+id/tvLogo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/rectangle_bordered"
android:fontFamily="#font/aldrich"
android:lineSpacingExtra="12sp"
android:padding="20dp"
android:text="I am a text"
android:textAlignment="center"
android:textColor="#FFFFFF"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
logo_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="2000"
android:fromXDelta="0%"
android:fromYDelta="-50%" />
<alpha
android:duration="1500"
android:fromAlpha="0.1"
android:toAlpha="1.0" />
</set>
and MainActivity.kt
class MainActivity : AppCompatActivity() {
//Binding
lateinit var binding: ActivityMainBinding
//Variables
lateinit var topAnimation: Animation
lateinit var logo: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setContentView(R.layout.activity_main)
logo = findViewById(R.id.tvLogo)
topAnimation = AnimationUtils.loadAnimation(applicationContext, R.anim.logo_animation)
logo.startAnimation(topAnimation)
//This does not work
//binding.tvLogo.startAnimation((topAnimation))
}
}
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setContentView(R.layout.activity_main)
What you're doing here is
inflating a layout, storing it in binding
displaying that inflated layout
replacing that and displaying another inflated copy of the layout
binding.tvLogo.startAnimation((topAnimation))
This doesn't work because you can't see it happening - you're animating the View on the first layout you inflated, but it's the second one that's being displayed, and you're not interacting with that.
logo = findViewById(R.id.tvLogo)
logo.startAnimation(topAnimation)
Whereas this one works because you're looking up tvLogo on the currently displayed layout (the second one) and then animating that View. Because it's the one on the screen, you see the results
Basically, if you ever find yourself inflating a layout more than once, that's a sign you're doing something wrong (there can be situations where you would, but in that case you'd know why you're doing it!). And the same goes for multiple setContentView calls
I have surprisingly been stuck on this one for a little while.
User Story:
The user should see a Loading Dialog that can be reused through the application with a transparent background so you only see the progress spinner and the text under the progress spinner.
Currently, I have a DialogFragment that inflates this XML to present itself:
<?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="wrap_content"
android:background="#android:color/transparent">
<ProgressBar
android:id="#+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="1"
android:background="#android:color/transparent"
android:indeterminateDrawable="#drawable/loading_spinner"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.499" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:alpha="1"
android:background="#android:color/transparent"
android:text="Loading..."
android:textColor="#FFFFFF"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/progressBar" />
</androidx.constraintlayout.widget.ConstraintLayout>
I am trying to set the transparency in the background and have had these results:
alpha set changes children elements to transparent as well
above XML setting does nothing and shows a white background
Setting it programmatically(See below) also does nothing and displays it white.
LoadingDialog():
class LoadingDialog(): DialogFragment() {
private var _binding: FragmentLoadingDialogBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
this.dialog?.window?.setBackgroundDrawableResource(android.R.color.transparent)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState:Bundle?
): View? {
_binding = FragmentLoadingDialogBinding.inflate(inflater, container, false)
return binding.root
}
//Always do this in Dialog to maintain memory management
override fun onDestroy() {
super.onDestroy()
_binding = null
}
}
How can I get the above LoadingDialog to present the Loading Progress Spinner and the Text without the white background?
I think you should call onCreate() method before setting the background to transparent after which you should set the view for your dialog. Try this
val dialogBinding = // inflate dialog here using dataBinding for example
val customDialog = AlertDialog.Builder(this, 0).create() // works with other dialogs as well
customDialog.apply {
window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
setView(dialogBinding?.root)
}.show()
I hope this helps you solve your problem. For more information about Dialogs in Android, please refer to my article on section.io
something else, consider removing the transparent background on your root viewGroup as shown below
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent">
edit to
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="wrap_content">
I'm am new to Kotlin I try to create a Shopping List app and I encountered a problem with a RecycleView inside a fragment.
In the fragment, I have a button that a user click and adds Item to the list but I got error when I tried to add the layout manager inside the OnCreateView function.
I tried this:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_shopping_list, container, false)
rv_shoppinglist.layoutManager = LinearLayoutManager(context) \\ this is where i get ERR
return view
}
and i got an ERR -> java.lang.IllegalStateException: rv_shoppinglist must not be null
So i added this line rv_shoppinglist.layoutManager = LinearLayoutManager(context)
on different function
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
rv_shoppinglist.layoutManager = LinearLayoutManager(activity)
}
and now the app works and when I user add the item to the list it does show the items on the RecycleView but instead of displaying them line underline it's displaying them with a screen size gap
Image:
edit:
This is the XML file for RV_CHILD:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/tv_item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
And this is an XML file for shopping_fragment
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".fragments.shopping_list">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_shoppinglist"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab_shoppiglist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:src="#drawable/ic_plus"
android:layout_margin="16dp" />
</RelativeLayout>
</FrameLayout>
You need to set relative layouts height to wrap_content otherwise it will take up the whole screen
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tv_item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
As a commenter pointed out, it appears that your viewholder layout height (RV_CHILD in your case) is set to match_parent when it should probably be wrap_content
I am wondering why adding viewBinding to my app, makes the XML root display in full screen when running the app. The root doesn't display in full screen in the designer view inside Android Studio.
Due to the root displaying in full screen, I had to add android:gravity="center" to vertically align the children in the center. While I don't think this should be a problem, I'm still interested in knowing why this is the case.
I have the following code;
<?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:gravity="center"
android:layout_gravity="center_vertical"
android:background="#color/colorAccent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="1"
android:textSize="30sp" />
<Button
android:id="#+id/roll_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/roll"/>
</LinearLayout>
package com.example.diceroller
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.diceroller.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
binding.rollButton.text = "testBind"
setContentView(binding.root)
}
}
I am not sure but I think that when You execute this setContentView(binding.root) You are setting a linear layout as fullscreen.
setContentView Android Docs
Set the activity content to an explicit view. This view is placed directly into the activity's view hierarchy. It can itself be a complex view hierarchy. When calling this method, the layout parameters of the specified view are ignored. Both the width and the height of the view are set by default to ViewGroup.LayoutParams#MATCH_PARENT. To use your own layout parameters, invoke setContentView(android.view.View, android.view.ViewGroup.LayoutParams) instead.
To do make it looks like in the preview You can write this code.
XML:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="#color/colorAccent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="1"
android:textSize="30sp" />
<Button
android:id="#+id/roll_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Roll" />
</LinearLayout>
</FrameLayout>
</layout>
MainActivity.kt:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
binding.rollButton.text = "Test Roll"
setContentView(binding.root)
}
}
Tip: To convert fast Your layout to data binding layout use: Alt + Enter ➡ Convert to data binding layout