I have a custom view (MyView) which extends SurfaceView in which I override the onDraw method. I create an instance of this view dynamically with a custom constructor:
MyView myView = new MyView(...);
In this constructor I call the super(Context context) method.
After that, I wrap my custom view in a RelativeLayout like this:
((RelativeLayout) findViewById(R.id.container)).addView(myView);
And this is the layout file that I am using:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Test"
android:layout_below="#+id/container"/>
</RelativeLayout>
The problem is that the TextView is at the top of the screen instead of being below the RelativeLayout (with the #+id/container id). As it will be without the android:layout_below property.
It behaves like my custom view (MyView) does not set its dimensions. I tried to use the setLayoutParams() but it did not change anything.
I think the problem is that your container view is inflated and laid out before your custom view is added to it and so gets a height of 0 since it has no content. After you add it to its container, a relayout is forced at which point the container asks the child view to measure itself. Since the height of the container is wrap_content, the child needs to report a specific height at this point. My guess is that your MyView class is not doing this.
An easy thing to do in order to set the height of your MyView objects is to override and implement the onMeasure() method.
Related
I'm trying to create a fragment with height of 80dp, and at Design section it seems to work pretty well, but when I run the app on my device, RelativeLayout somehow takes a fullscreen. I use android:layout_alignParentBottom="true" for the SeekBar, but as far as I know it shouldn't take fullscreen if Layout's height isn't wrap_content. Here is the XML code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="80dp"
android:background="#bbbbff">
<SeekBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/progressBar"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="#+id/playButton"/>
<Button
android:layout_width="60dp"
android:layout_height="60dp"
android:text="play"
android:layout_alignParentRight="true"
android:id="#+id/playButton"/>
</RelativeLayout>
EDIT 1: I just tried to use this layout for an activity and it doesn't take fullscreen anymore, but I still have a problem with fragment. Also, I don't change Layout's height programmatically.
EDIT 2: I use fragmentTransaction.add(R.id.musicBarContainer, musicProgressBar) to add the fragment to activity, where musicProgressBar is an instance of fragment java class. The musicBarContainer XML code is
<FrameLayout
android:id="#+id/musicBarContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
</FrameLayout>
In onCreateView I use View view = inflater.inflate(R.layout.music_progress_bar, null);
From the RelativeLayout doc:
Class Overview
A Layout where the positions of the children can be described in relation to each other or to the parent.
Note that you cannot have a circular dependency between the size of the RelativeLayout and the position of its children. For example, you cannot have a RelativeLayout whose height is set to WRAP_CONTENT and a child set to ALIGN_PARENT_BOTTOM
Class documentation
Which is exactly your case. RelativeLayout can not do that.
for more detail visit this answer : RelativeLayout is taking fullscreen for wrap_content
In MusicProgressBar fragment class, instead of
View view = inflater.inflate(R.layout.music_progress_bar, null);
you should write
View view = inflater.inflate(R.layout.music_progress_bar, container, false);
Try setting the height of seekbar to 20dp and check. I think its wrap_content is overriding the parents height parameter somehow.
My question is if is possible add an ImageView in a SurfaceView without XML. If yes, how? I have a main class that has the function of GamePanel, and for apply a Method i need to call it with an ImageView, but i don't know if it is possible. Thanks you in advance.
You need to read about the View and ViewGroups provided by the Android Framework.
I am giving the quick understanding to propose the solution.
Crash Course about View & ViewGroup
At the root of the Android UI system, everything is View.
What is a View?
It is a single widget / UI component that can be displayed on the screen. The View includes Buttons, TextViews, ImageViews, SurfaceView. They can not contain any child view i.e. They can not hold declaration for the any other child view
Following XML definition is incorrect: A view can not hold another view
<SurfaceView
android:id="#+id/textSurfaceView"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</SurfaceView>
What is ViewGroup?
Inherited from View and designed to contain and arrange more than one View also called as Child views. The various ViewGroups are LinearLayout, RelativeLayout, FrameLayout etc.
Following XML definition is Correct: A ViewGroup can hold another view
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="#+id/surfaceView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
Here comes the solution
Step-1: Add a ViewGroup in your XML wrapping the existing SurfaceView. As mentioned already the ViewGroups are LinearLayout, RelativeLayout, FrameLayout etc.
res/layouts/your_layout.xml
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/baseFrame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="#+id/surfaceView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
Step-2: At the time of view creation add an ImageView to the FrameLayout. onCreate() activity.
setContentView(R.layout.your_layout);
FrameLayout baseFrame = (FrameLayout) findViewById(R.id.baseFrame);
ImageView imageView = new ImageView(this);
imageView.setWidth(/*As per your need*/);
imageView.setHeight(/*As per your need*/);
imageView.setId(/*Any unique positive Number*/ R.ids.imageView1); <= Required to access this view later
/*Set the layout parameters such as layout_gravity as well.*/
baseFrame.addView(imageView);
Step-3: I know you must be wondering about the ImageView Id. I am giving the quicker way to assign an ID to a View.
Create a file ids.xml at res/values
Fill the following details.
<resources>
<item type="id" name="imageView1" />
</resources>
Step-4: Passing an ImageView to the method
ImageView myImageView = (ImageView) findViewById(R.id.imageView1);
methodToBeCalled(myImageView);
I hope that helps.
Happy Coding!!!
I have a list view displaying items from a custom adapter which extends ArrayAdapter. Each item is a custom layout with a RelativeLayout being the root view. Now, I want this RelativeLayout to be centered horizontally inside the list view, but I everything I tried seems to fail.
Here's my custom adapter getView method:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = mInflater.inflate(R.layout.screens_listview_row, parent, false);
return row;
}
And here's the file screens_listview_row.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root"
.....
android:layout_gravity="center_horizontal" >
</RelativeLayout>
At first, it seemed like my layout parameters in the RelativeLayout were completely ignored, and it really was the case because i used inflate(R.layout.screens_listview_row, null), what is a problem like this answer says.
So now the only thing ignored is the layout_gravity parameter. I also tried layout_marginLeft (Everything in this layout is in absolute sizes so I could center it myself by giving a left margin...) but Android ignored it too. What is the problem here?
try to use gravity instead of layout_gravity (as i know gravity is for the content of layout)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root"
.....
android:gravity="center_horizontal" >
</RelativeLayout>
I didn't find out how to control the position of the items inside the ListView, so instead I made the ListView width exactly as the items' width, then controlled its position (Which practically controls the items' position).
I want to know how the LayoutParams will work on LayoutInflator. And what is difference between:
LinearLayout childLayout=(LinearLayout)inflater.inflate(R.layout.childitemlayout, null); //FIRST WAY
LinearLayout childLayout=(LinearLayout)inflater.inflate(R.layout.childitemlayout, container,false); //SECOND WAY
Because, both methods gives me different result.
Actually second inflate method are gives me correct result for both child layout change, but First method will gives me different result.
Here is my code:
MainActivity.Java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout mainLayout=(LinearLayout)findViewById(R.id.mainLayout);
LayoutInflater inflater=LayoutInflater.from(getApplicationContext());
for(int i=0;i<10;i++){
LinearLayout childLayout=(LinearLayout)inflater.inflate(R.layout.childitemlayout, null); //First WAY
// LinearLayout childLayout=(LinearLayout)inflater.inflate(R.layout.childitemlayout, mainLayout,false); //SECOND WAY
mainLayout.addView(childLayout);
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
</LinearLayout>
childitemlayout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="80dp"
android:layout_height="80dp"
android:orientation="vertical"
android:background="#525f67">
<TextView android:id="#+id/btn"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Button"
android:gravity="center"
/>
</LinearLayout> <!-- Both ways gives different result -->
<!--
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#525f67">
<TextView android:id="#+id/btn"
android:layout_width="80dp"
android:layout_height="80dp"
android:text="Button"
android:gravity="center"
/>
</LinearLayout> Both method gives SAME result -->
The main difference between the two inflate() methods is the second parameter(the ViewGroup parameter) and its use in setting the proper LayoutParams for the root view of the inflated layout file. This is important because the LayoutParams keep various layout attributes of the view(like width, height, positioning rules etc) and are required so the parent of that view can properly show the view.
The first method basically says: build the hierarchy view from this layout file but don't assign LayoutParams to the root of the inflated hierarchy(maybe because the parent isn't know yet), also don't attach the inflated view to a parent.
The second inflate method says: build the hierarchy view from this layout file and also assign the proper LayoutParams(based on the second parameter given to the inflate method) to the root of the inflated hierarchy, also don't attach the inflated view to a parent.
In the first case, the root of the inflated layout file(R.layout.childitemlayout) will not have any LayoutParams set on it(the inflate method didn't assign any because the second parameter is null and it doesn't know which type of LayoutParams to generate), so your fixed width/height values are lost. Later when you'll do mainLayout.addView(childLayout); the mainLayout will check the LayoutParams of the childLayout, see that those are null and will automatically set an instance of the LayoutParams(using its generateDefaultLayoutParams() method). This method, in the particular case of a horizontal LinearLayout, will return an instance of LayoutParams where the width/height will be set to WRAP_CONTENT. So your childLayout will end up with WRAP_CONTENT as its size instead of the fixed values you set on them.
In the second case, the inflate method sees that you suggested the LinearLayout mainLayout as the ViewGroup used for generating the LayoutParams. This means that the fixed values(that you used for the width/height) retrieved from the layout file can be stored in a proper instance of the LayoutParams. When you'll do mainLayout.addView(childLayout);, mainLayout will see that childLayout has the proper LayoutParams instance(which has the values used in the layout file) and doesn't call its generateDefaultLayoutParams().
I have a layout whose root ViewGroup has two children only one of which is always visible. The other child's visibility will be set at runtime to View.GONE when not applicable.
When both children are visible, the heights are set to wrap_content and the layout looks great. The problem is that I'd like to expand the visible view to match_parent when the other is gone.
Is there any way to accomplish this or the equivalent?
You can change any View's layout like this:
view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
The constructor takes width then height as in: new LayoutParams(int width, int height).
Also there is a LayoutParams class for each type of ViewGroup. Make sure you import the one that refers your particular ViewGroup. So if your ViewGroup is a LinearLayout use:
import android.widget.LinearLayout.LayoutParams;
I tried unsuccessfully figuring this strategy out
I'm not certain where you had trouble, but this approach only requires a couple extras lines:
// When you want to show both views
view1.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
view2.setVisibility(View.VISIBLE);
...
// When you want to hide the second view
view1.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
view2.setVisibility(View.GONE);
If you hide / show the views multiple times you can save a reference to each LayoutParams object rather than repeatedly creating new objects.
Have you tried working with android:layout_weight?
I put together this small example. Below I added a picture showing both views visible (left) and how it looks like with view2 visibility set to GONE (right). As you see, view1 uses up all available space then.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<View
android:id="#+id/view1"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#ff0000" />
<View
android:id="#+id/view2"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#0000ff" />
</LinearLayout>