I'm using a relative layout in Android, and when adding a view to the bottom of the screen the view is placed lower than the actual bottom of the screen, where the user cant actualy see it.
view.setY(container.getBottom()-view.getHeight());
container.addView(view);
container is a RelativeLayout. i have also tried to use container.getHeight() which gave me the same result, and all the other solutions i found where using the xml file, which doesnt work for me since i need to add the view dynamically in a random position above the bottom of the screen, meaning
view.setY(container.getHeight()-Common.random.nextFloat()*100-view.getHieght());
this is the XML
<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:id="#+id/layout"
tools:context="il.co.ovalley.dashvsponypolice.app.MainActivity">
</RelativeLayout>
and the View im trying to add:
public class GameView extends ImageView{
public GameView(RelativeLayout container) {
super(container.getContext());
m_container=container;
container.addView(this);
}
}
public class Cop extends GameView {
public Cop(RelativeLayout container) {
super(container);
m_isShooting=false;
m_LoadingTime=10;
m_isLoading=false;
m_xSpeed=1.5f;
setY(container.getHeight()-Common.random.nextFloat()*100-getHeight()/*-getPaddingBottom()*/);
float x=(Common.random.nextFloat()*m_container.getWidth());
setX(x);
drwableState=0;
changeDirection();
}
I have tested that on different versions of android and screen sizes and got the same result. so far, the only solution I found was subtracting an arbitrary int from the container's height which seems ok on one device and hope for the best for the others, I'm sure there is a better solution.
thnx
Why don't you just place the view at the bottom of the screen with ALIGN_PARENT_BOTTOM and then apply a random padding?
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
view.setPadding(0, 0, 0, randomValue); // left, top, right, bottom
container.addView(view, params);
All this calculating with the view.getHeight() is not good. Doing it like this works without you having to manage any of that yourself.
Related
My app utilizes a custom FrameLayout that contains a PlayerView and another custom FrameLayout ("DrawView"). The goal is to draw customized shapes on the FrameLayout that appear on top of the video being played.
In the layout, I have PlayerView first, then the DrawView:
<!-- customized FrameLayout encompassing ViewPager2 and DrawView, which implements that capability of
detecting taps -->
<com.reddragon.intouch.utils.ViewPager2Host
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:id="#+id/viewpager2host"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
tools:context=".ui.MediaPlayerActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/activity_media_player_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.viewpager2.widget.ViewPager2>
<com.reddragon.intouch.ui.drawview.DrawView
android:id="#+id/drawView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
The DrawView component is used to draw shapes and text over the top of the video, and so I need to resize it to match the size and position of the rect that represents where the video is played.
I have the logic correctly implemented to do this, and I have implemented VideoListener and placed this logic within onSurfaceSizeChanged().
This works fine - and as you can see from the screenshot, the red line (representing the bounds of the enclosing parent ViewPager2Host) and the green line (representing the bounds/placement of the video surface view I calculated at runtime for this particular video) is correct:
Here is my question - onSurfaceSizeChanged() gets called multiple times, and I only want to do the calculation of size and location once for DrawView. From my testing it appears that as long as the ViewPager2Host parent does not change dimensions, then onSurfaceSizeChanged() gets called twice, and the second time is the "final" dimension.
Can anyone confirm that this is the case? Or are there cases - perhaps where the parent dimensions exactly match the video surface view dimension that onSurfaceSizeChanged() would only be called once?
Or is there some way to know when the surface size is 'final'?
I'm trying to implement some sort of 'if video is initializing then' logic so that only AFTER all layout is complete and the video surface rect has been finalized, do I calculate the size and placement of DrawView.
The simple answer to my original question appears to be: NO - there is no guarantee on how many times this gets called in the normal rendering pipeline, except that it is called at least once.
Upon further testing, it also becomes clear that even after onPlayerStateChanged() gets called with STATE_READY, the video size is not yet stable (I've seen numerous times now that onSurfaceSizeChanged() gets called with updated values even after STATE_READY gets called).
So my original idea of handling everything in onPlayerStateChanged() after playWhenReady is TRUE does not now seem to be a good answer.
Still looking for how I can tell the video surface has settled down to the size it thinks is "final" for playing the video!
As a refresher, my customized FrameLayout has three "layers" (each of which completely fill the holder associated with the current ViewPager2 adapter):
Media display (either a Glide implementation for images, or ExoPlayer2 PlayerView for Media)
DrawView (customized FrameLayout which holds the various shapes drawn on top)
FrameLayout (holding an indeterminant progress bar and text shown when video media from the Internet is taking a while to buffer)
My solution ended up being (upon the "next" item in the ViewPager2 recyclerview being ready to display a video):
Initially hide the DrawView and Media Display layers
Show the "loading" components
setPlayerWhenReady(true) on the ExoPlayer
prepare(mediaDataSource)
Within the onPlayerStateChanged() callback from ExoPlayer that my activity implements, test for both playWhenReady being TRUE and the plabackState being STATE_READY, and then
remove the "loading" views
set the ExoPlayer view visible
calculate the various drawing widgets within DrawView given the ExoPlayer's videoSurfaceView dimensions and position
set the DrawView Visible.
I'm not sure why, but it seems overriding other callbacks like those from VideoListener didn't "jog" the views to draw themselves properly. I saw numerous cases where onDraw() of the DrawView class would be called, but neither onDraw of the widgets, or onDispatchDraw of the DrawView class would be called.
I am new to Android development and Android studio. I'm using Android Studio 3.6.1 . I'm having trouble understanding the "Layouts" options in the Design Palette. First, I don't see a "RelativeLayout" option. I realize many feel this is superceded by the ConstraintLayout, but it seems to me it should be a choice. Second, I don't see how to even use these layout options. If I drag one to an existing design, nothing happens. I thought maybe it would replace the root layout, but doesn't seem to. It doesn't create a child layout (if such a thing is possible). My code is just a simple "MainActivity" class with "setContentView(R.layout.activity_main);" in the onCreate() method. I have been tinkering with the activity_main.xml file to learn UI concepts. I can type in manual changes to change the layout to RelativeLayout, but it wasn't obvious what the classpath of the RelativeLayout class was, it is not in the same package as the ConstraintLayout class. I'm trying to use the power of the Android Studio IDE to discover options and build code, but I'm not finding how to use it for Layout options. I tried emptying the "activity_main.xml" file and then dragging a Layout from the palette, but nothing happens. I can delete the "activity_main.xml" file and create a new one, but when it prompts for a layout, there is no discovery to help choose one, it seems you have to know the package.
How can these Layouts in the Design Palette actually be used in the IDE? Can RelativeLayout be added to the list? Are there other missing Layouts?
package com.example.test;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.widget.RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
</android.widget.RelativeLayout>
Something changed and I can now right-click a Layout and "add to design" or drag it to the design. I can also right-click the Layout in the component tree and convert to another layout, including RelativeLayout. I had added a Calendar component to my design for the heck of it and built and run in the emulator. After that, I deleted the Calendar and found I was able to now drag the layout components or convert the root component. So I'm comfortable with use of Layouts in the Palette. I am still unclear how to discover Layouts when creating a new layout XML file when it asks for "root tag". But I realize you don't need a full path, just the class name it seems, apparently the IDE finds the class. The glue behind the scenes I'll need to learn more about.
An app uses ExpandableListActivity, and the usage of ExpandableListView is standard based on the document:
<ExpandableListView
android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:divider="#android:color/transparent"
android:dividerHeight="5dip"
android:layout_marginTop="10dip">
</ExpandableListView>
Android Studio 3.2 has the following warning:
How can I get rid of the warning?
This is probably a typo. Change it to:
"#android:id/empty"
and
"#android:id/list"
See also https://developer.android.com/reference/android/app/ListActivity
ListActivity has a default layout that consists of a single,
full-screen list in the center of the screen. However, if you desire,
you can customize the screen layout by setting your own view layout
with setContentView() in onCreate(). To do this, your own view MUST
contain a ListView object with the id "#android:id/list" (or R.id.list
if it's in code)
I don't know what is ( id="#id/android:list")
give it an normal id ( #+id/androidlist )
and handle it in your code
but if you learn how to work with ExpandableListView
I prefer this link tutorial for you ExpandableListView Link
GL sir
How can I set a png icon on a button in the MainActivity?
I have to change this icon many times during the program, so I can't set the image in the xml code.
But in the xml it is in the center of the button, so it's perfect and well stretched
android:drawableTop="#drawable/x"
In the MainActivity I don't know what to do
bt.setCompoundDrawablesWithIntrinsicBounds(null, x, null, null);
Use the below code:
Drawable top = getResources().getDrawable(R.drawable.x);
bt.setCompoundDrawablesWithIntrinsicBounds(null, top , null, null);
To Add the image at centre you can use imageButton:
Add the below image button in place of your button in layout xml.
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageButton" />
Get the imageButton and set drawable:
ImageButton ib = (ImageButton)findViewById(R.id.imageButton);
ib.setImageResource(R.drawable.x);
Hope this helps.
If you are targeting API level 17 or higher, you can accomplish this with just one simple line:
bt.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.x , 0, 0);
This method takes drawable resource ID's as arguments, so there is no need to get the drawable yourself using getDrawable(). Passing a 0 as argument means no icon on that side.
Good luck!
I have an ImageView inside a RelativeLayout that I added programmatically (The ImageView is added by code, not the RelativeLayout.)
If I had added the ImageView by XML, I would have done this:
<ImageView
android:id="#+id/login_loadingimage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="#drawable/imagefilename"
android:visibility="invisible"
/>
But now I want this done programtically. How do I get the centering right? I have tried creating RelativeLaout.Parameters but whe I create them using
RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(this, null); //[1]
p.AddRule(...);[2]
An exception is thrown at line 1. In addition I wouldn't know how to apply these LayoutParameters on ViewGroup.LayutParameters anyway.
Also, I cannot just make ViewGroup.LayoutParameters because
1. They do not seem to have the Centering (Horizontal and Vertical) elements I need.
2. Every example seems to indicate there is a Constructor that simply takes Layout_Width and Layout_Height as parameters, but there is not.
Before someone says to add a layout first, please tell me how to center the layout in code as well. Thanks.
Please help.
The way to do it is simple:
Create xaml you want of JUST the component - put the file in the layout folder.
Then use the inflating service to inflate the control inside the code you want (make sure to create the LayoutInflator as follows):
LayoutInflater _inflatorservice = (LayoutInflater)this.GetSystemService(Context.LayoutInflaterService);
Then simply call this:
_inflatorservice.Inflate(Resource.Layout.[control], parent);
and Bob is your mother's brother!