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!!!
Related
I have a simple layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:padding="15dp">
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/scrollLayout">
</LinearLayout>
</ScrollView>
</RelativeLayout>
Now, I inflate the outer RelativeLayout to retrieve the inner LinearLayout to put items in it.
RelativeLayout relative = (RelativeLayout) LayoutInflater.from(activity).inflate(R.layout.gradient_pick_view, null);
LinearLayout view = (LinearLayout) relative.findViewById(R.id.scrollLayout);
After that I created a method to add some buttons to it:
for(int i=0;i<10;i++){
LinearLayout wrapper = (LinearLayout) LayoutInflater.from(activity).inflate(R.layout.button_wrapper, null);
Button button = (Button)wrapper .findViewById(R.id.button);
view.addView(layout);
}
Everything works fine, but it doesn't scroll.
What am I doing wrong here?
Here's the screenshot (displaying 7 of 10 buttons):
I forgot to mention - I'm using a MaterialDialog library and add this RelativeLayout as a custom view to a dialog.
Try to set the following attribute to your scrollview,
android:fillViewport="true"
above attribute is used to make your scrollview to use entire screen of your application.
I had a false parameter passed to a customView in a MaterialDialog.
dialog = new MaterialDialog.Builder(activity)
.title(R.string.about)
.customView(view, true)
.positiveText(R.string.changing_fragments)
.show();
As doc says:
If wrapInScrollView is true, then the library will place your custom view inside of a ScrollView for you. This allows users to scroll your custom view if necessary (small screens, long content, etc.). However, there are cases when you don't want that behavior. This mostly consists of cases when you'd have a ScrollView in your custom layout, including ListViews, RecyclerViews, WebViews, GridViews, etc. The sample project contains examples of using both true and false for this parameter.
Now it's working.
I have a GridLayout-based View to which I am dynamically adding several ImageButtons. I'm trying to understand why the ImageButtons are styled correctly when I inflate them from a layout xml file, but not when I create them using the ImageButton constructor directly.
The GridLayout and ImageButtons were previously both defined in the same layout .xml file (and rendered as expected):
<ScrollView
style="#style/my_list_style"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="12dp">
<GridLayout
android:id="#+id/my_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
<!-- These ImageButtons are being converted to dynamic. -->
<ImageButton
style="#style/my_button_style"
android:src="#drawable/image1" />
<ImageButton
style="#style/my_button_style"
android:src="#drawable/image2" />
</GridLayout>
</LinearLayout>
</ScrollView>
To convert the ImageButtons to dynamic, I first removed them from the layout file and used code like the following to add them at runtime:
ImageButton imageButton = new ImageButton(context, null, R.style.my_button_style);
imageButton.setImageResource(R.drawable.image1);
parent.addView(imageButton);
But the buttons failed to render properly; they are not centered, and their sizes do not appear to be correct/uniform.
I then tried creating a new layout file, containing nothing but the ImageButton and its style:
<ImageButton
style="#style/my_button_style"/>
When I inflate this layout into the GridView at runtime, everything looks as expected:
LayoutInflater inflater = LayoutInflater.from(context);
ImageButton imageButton = (ImageButton) inflater.inflate(
R.layout.my_button_layout, parent, false);
imageButton.setImageResource(R.drawable.image1);
parent.addView(imageButton);
Why does inflating the view with LayoutInflator give different results than creating the button directly from its constructor?
Because when you create ImageButton manually, you do not specify its parent, hence it doesn't know the layout params of its parent and can't be laid out as you expect.
On the other hand, when you inflate it via LayoutInflater, you are specifying the parent. Then correct layout params are being passed to children. That's why you see difference.
Have a look at detailed article by Dave Smith.
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.
I want to create a custom layout to reduce redundancy in the code. Currently every layoutfile has about 30 Lines of code which are identical.
My goal was to create a custom layout/view which can hold in itself children.
<BaseLayout xmlns:...>
<!-- Normal Content -->
<Button />
<Label />
</BaseLayout>
While the above xml holds most of the content, the BaseLayout is in itself an xml containing other views and functionality:
<FrameLayout xmlns:...>
<LinearLayout><!-- contains the Header--></LinearLayout>
<LinearLayout><!-- INDIVIDUAL CONTENT HERE--></LinearLayout>
<FrameLayout><!-- contains the loading screen overlay --></FrameLayout>
</FrameLayout>
So all children from the above xml should be inserted into second linear-layout. I have already succeeded into doing so. But am confronted with layout problems (match parents does not match parents and only wraps)
My approach was extending the LinearLayout with following logic:
/**
* extracting all children and adding them to the inflated base-layout
*/
#Override
protected void onFinishInflate() {
super.onFinishInflate();
View view = LayoutInflater.from(getContext()).inflate(R.layout.base_layout, null);
LinearLayout linearLayout = (LinearLayout) view.findViewById(R.id.base_layout_children);
while(0 < getChildCount())
{
View child = getChildAt(0);
LinearLayout.MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams();
removeViewAt(0);
linearLayout.addView(child, layoutParams);
}
this.addView(view);
}
Is there a better, cleaner approach to capsule the xml and reuse a basis layout? How do I fix the match_parent issue?
While writing this post and thinking hard how to explain best, the solution for the match_parent issue became clear. Though the question remains if there is a better approach for the whole problem.
//Solution:
this.addView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
//wrong:
this.addView(view);
Suppose you have two layout files. common_views.xml and layout_main.xml. You can include content of one layout file into another like this.
<?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"
>
<include
android:id="#+id/common"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="#layout/common_views" />
<WebView
android:id="#+id/webView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/common"
>
</WebView>
</RelativeLayout>
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.