I have a frame-layout defined in xml a follows:
//pseudo code
<FrameLayout
android:height = "match_parent" // same for width
android:background="#android:color/white"
padding = "20dp"
id = "polygraph"
layout_gravity="center"/>
I access this xml view via code as such:
LayoutInflater inflater = this.getLayoutInflater();
frameInflate = (FrameLayout) inflater.inflate(R.layout.mframe,null);
frar = (FrameLayout)frameInflate.findViewById(R.id.polygraph);
I create the following image-view dynamically but somehow it doesn't show inside this frame-layout which is one of many views inside another frame-layout that holds all the views of my User-Interface
view1 = new ImageView(this);
view1.setAdjustViewBounds(false);
matrix = new Matrix();
view1.setScaleType(ImageView.ScaleType.Matrix);//I have tried: ScaleType.Center it did not work at all
view1.setImageMatrix(matrix);
view1.setBackgroundColor(Color.GRAY);
params11= new FrameLayout.LayoutParams(200,300,Gravity.CENTER);
view1.setLayoutParams(params11);
DummyDraw drawD = new DummyDraw(this);
view1.setImageDrawable(drawD);
frar.addView(view1);
//somewhere down on onWindowsFocusChange()
frar.invalidate(); //try to invalidate to see if it will show the imageview
No image-view shows at all. I have tried different ways, such as:
frar.addView(view1,params11); //did not work
//instead of view1.setImageDrawable
view1.setBackground(drawD); //nothing
view1.setImageResource(R.drawable.somerandomdrawable);//nothing
I have no idea why this view isn't showing. Could it be the drawable "drawD"? If it is this drawable, then why isn't showing at least the background color "gray"
which I set in the code? I have tried to get rid of the ScaleType.Matrix to something else, such as ScaleType.Center, but nothing seems to work.
Any advice or suggestions will be appreciated
thanks
I had ran into the same problem a few months ago. But I did forget how to handle it. LayoutInflater wasn't needed to solve the problem. Seems like I can't do this call inside onCreate() "(FrameLayout)findViewById(R.id.polygraph)" and then try to add my programmatically created image-view to my xml layout element. It gave me a null pointer exception all the time.
Moving both calls way after the layout pass, such as on onStart() or onWindowsFocusChanged() works well. The image-view is added to the xml frame-layout, which in the end it works well for my app, since I had the intentions of adding the image-view well beyond the layout pass.
Related
I am using the scrolling activity generated by Android Studio. So something like this:
It uses an #include tag in the XML to load the content of the activity.
I need to change the content inside this NestedScrollView to something else. So I have been using this:
LayoutInflater inflater =
(LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
progressContent = inflater.inflate(R.layout.content_progress, null);
scrollView.removeView(normalContent);
scrollView.addView(progressContent);
And it works, but it doesn't use the ConstraintLayout of the progressContent correctly, it ignored all the bias values and only keeps hard set margins and paddings.
In this question, people suggested to use ´setContentView` but since I only have to change the inner content, not the whole layout, it's not the right solution:
How to set layout dynamically in android
In this one it was suggested to use ViewStubs instead of #include:
How can I programmatically include layout in Android?
But this only resulted in a completely broken CollapsingToolbarLayout and the layout parameters of the second view got discarded regardless.
What is the correct way of doing this?
I want to create this sort of a view where the cross should be separate image view as I want it to be clickable. How can I achieve this ?
It would be great If I can create this view programatically as I am a dynamic list of images and I am programatically creating the image Views. All I need now is to add the overlapping imageview as well.
Thanks in advance
Use FrameLayout and you can overlay views on top of each other
Ex:
FrameLayout frame = (FrameLayout) findViewById(R.id.frame);
ImageView image = new ImageView(this);
iv.setImageResource(R.drawable.image);
ImageView cross = new ImageView(this);
i.setImageResource(R.drawable.cross);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.RIGHT | Gravity.TOP;
i.setLayoutParams(layoutParams);
frame.addView(image);
frame.addView(cross);
Create a RelativeLayout programmatically, which contains two ImageViews. Place your image in the first one, and your second image in the second one. Adjust the margins accordingly to place it in the top right corner.
First create a completely new layout to use as an placeholder for example "partial_layout.xml". Then in your code first make a LayoutInflater with something like this:
LayoutInflater mInflater = (LayoutInflater) this.getSystemService(this.LAYOUT_INFLATER_SERVICE);
then try to get a fresh copy of this layout with something like this:
View convertView = mInflater.inflate(R.layout.partial_layout, null);
now put your current data to this view, and finally add this view to your content view.
If you create a list of views, you can still use XML by inflating it only when needed - just watch the lecture "the world of listView" in order to do it correctly. Using ListView is much more efficient than creating as many views as the number of items to show (for example, if there are 100 images to show, only those that are on screen need to be created).
Anyway, the xml can contain either FrameLayout or RelativeLayout as the root view, and you just put the 2 imageViews according to the right position you wish to have. You can use the UI designer for this, or edit the XML itself by adding margin-top for the larger image. also, make sure the larger image is written there before the small one.
as for the clicking, you can use setOnClickListener on the small imaveView.
BTW, if it's just images, you should probably use GridView instead of ListView.
Right, this is a strange problem I have been toying with for a while now, hopefully maybe I am missing something you guys can draw my attention to!
LinearLayouts seem to be disappearing once I add any spacing using views and defining the weight (a method which works elsewhere in the project).
I have a custom Dialog (extends Dialog). In the onCreate() I use the method setContentView(generateDialog()) which returns a vertical LinearLayout.
The LinearLayout has three elements, one row of four custom category buttons (LinearLayouts), one row of sorting buttons (also LinearLayouts) and one ListView which populates the rest of the dialog and refreshes based on which button is pressed.
All is functional and working fine. Except when I attempt to space the buttons out evenly using my spacer method:
Dialog.java:
LinearLayout catBtns = new LinearLayout(context);
catBtns.setOrientation(LinearLayout.HORIZONTAL);
catBtns.setBackgroundResource(R.drawable.btn_cat_gradient_bg);
catBtns.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
catBtns.addView(space(1));
cat1Btn = new CatButton(context,this,act,"CAT1");
catBtns.addView(cat1Btn);
catBtns.addView(space(1));
cat2Btn = new CatButton(context,this,act,"CAT2");
catBtns.addView(cat2Btn);
catBtns.addView(space(1));
cat3Btn= new CatButton(context,this,act,"CAT3");
catBtns.addView(cat3Btn);
catBtns.addView(space(1));
cat4Btn = new CatButton(context,this,act,"CAT4");
catBtns.addView(cat4Btn);
catBtns.addView(space(1));
The space() method:
private View space(int space) {
View view = new View(context);
LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(0,0);
p.weight = space;
view.setLayoutParams(p);
return view;
}
What confuses me is that I have been using this method throughout the project and can't find as to why the category LinearLayout DISAPPEARS COMPLETELY when I add the spacers in between each button.
I use the same technique for the sorting buttons and it works perfectly! I use the same technique in another part of the project using slightly different versions of the same buttons (they are different class files though, because the onClickListener and some other stuff is slightly different)
Anyone have any clue?
I tried to build this in XML and it works fine. A possible difference is, that you do not set any LayoutParams for your buttons. Try something like that for every button:
cat1Btn = new CatButton(context,this,act,"CAT1");
catBtns.addView(cat1Btn, new LinearLayout.LayoutParams(0,0));
Short Story:
I have a layout "layout.xml", which gets replaced by another layout "success.xml" after a successful web request. Both layouts have an ImageView that provides the backgrounds to the layouts. These 2 backgrounds both need to be the same, and both are dependent on a user preference.
Longer Story: This all happens in a Fragmnet with an AsyncTask replacing the contentView with "success.xml" in onPostExecute after the web request. This happens as follows:
View view = getView();
view = null;
view = View.inflate(context, R.layout.success, null);
What I tried to do is give both ImageViews the following android:id="#+id/background_image" and then call
ImageView background = (ImageView)view.findViewById(R.id.background_image);
background.setImageResource(R.drawable.bg1);
This background-setting works for the initial view (layout.xml), but on trying to change to "success.xml", I get a NullPointException because background is null.
I've checked and the View's id is set to -1 while the original view's background_image id is set to something sensible and valid.
I've also tried setting the second view's background id like this: android:id="#id/background_image", i.e. without the '+', but still no luck.
The added complication is that it's not just 2 layouts, but about 5 that I need to do this for, so it would be really handy to recycle view id's.
Any help would be greatly appreciated.
Your code for replacing the fragment's view will not do what you want, the original view will remain the same as you change only a reference to that view and not the actual object.
To replace the view of the fragment with the new layout you could have another ViewGroup(for example a FrameLayout) in the basic layout (layout.xml) wrapping your current content(don't forget to give it an id) of layouts.xml(as I understand this is the basic layout). Then, when it's time to replace the layout you could simply do:
// remove the current content
((ViewGroup) getView().findViewById(R.id.yourWrapperLayout)).removeAllViews();
// add the new content
View.inflate(context, R.layout.success, ((ViewGroup) getView().findViewById(R.id.yourWrapperLayout)));
You could avoid adding an extra layout if, by any chance, all your five layouts have the same type for the root view(like a LinearLayout etc). In this case you would use the same code as above but you'll modify the other layouts file to use a merge tag. Also, you'll be looking for the id of the root in the layout.xml layout into which you'll add the content of the other files.
Then you could have the same ids, but you'll have to reinitialize any reference to the views(meaning that you'll have to search for the view again if you store a reference to the view(like a Button field in the fragment class)).
I am trying to create a simple game. I would like to populate a LinearLayout which I have defined in an XML with several RelativeLayouts. Each time the user presses a button I would like a child View to be added to the LinearLayout. Each RelativeLayout would change slightly based on the users input (which buttons were pressed, etc).
I essentially want to create a new RelativeLayout based on an XML layout file. I then want to manipulate some attributes of the RelativeLayout's child Views (specifically the src of some ImageViews) and add it to a LinearLayout. This in itself is not particularly difficult. I can get at each of the RelativeLayout's children using findViewById but I start having problems when I want to create n number of RelativeLayouts based on the same XML. I'm pretty sure duplicate IDs are causing crashes. Can a RelativeLayout work without using IDs? Should I try and find a different way of constructing the interface using different ViewGroups?
I'm not sure if what I am asking is even possible but I know that creating these items on-the-fly using the code alternative to the XML layouts is a horrible thought.
Thank you in advance.
EDIT: I lost my train of thought halfway through, the previous example had some bugginess. I've updated.
pedr0 has the right idea, but to clarify, you could try something to this effect (assuming you have a RelativeLayout defined in relative.xml). This isn't tested, but the general idea should be valid. You don't even have to do a separate method, you can do it inline in a click handler, or whatever, but I just did the addChildView method for the sake of example:
LayoutInflater inflater;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//get the LinearLayout that you plan to add rows to
LinearLayout linearLayout = (LinearLayout)findViewById(R.id.linear_layout);
//get the LayoutInflater from the system
inflater = getSystemService(LAYOUT_INFLATER_SERVICE);
//call getNewChildView with whatever drawable id you want to place
//as the source. If you want to pass in other types, just change
//the parameters (e.g. Drawable, Bitmap)
linearLayout.addView(getNewChildView(R.drawable.my_image));
}
public RelativeLayout getNewChildView(int resId) {
//inflates a copy of your RelativeLayout template
RelativeLayout rl = (RelativeLayout)inflater.inflate(R.layout.relative, null);
//this assumes an ImageView in your RelativeLayout with an id of image
ImageView img = (ImageView)rl.findViewById(R.id.image);
img.setBackgroundResource(resId);
return rl;
}
EDIT: I couldn't even work out how to use the code tags properly sigh
Thank you both for your quick responses. I had something very similar in mind and in fact was on the same track and using the LayoutInflator. I simplified your example a little as I do not need to pass the id of a drawable around.
LayoutInflater inflater;
private void drawGuess() {
// The top level LinearLayout to add to
LinearLayout topLevel = (LinearLayout) findViewById(R.id.guessList);
// get the inflater`
inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
// add the view (based on stored data elsewhere)
topLevel.addView(getLatestGuess());
}
private RelativeLayout getLatestGuess() {
//inflates a copy of your RelativeLayout template
RelativeLayout rl = (RelativeLayout)inflater.inflate(R.layout.guess_layout, null);
//this assumes an ImageView in your RelativeLayout with an id of image
ImageView guessOne = (ImageView)rl.findViewById(R.id.guess1);
guessOne.setImageResource(R.drawable.red);
}
Running this code works, the catch is it only works the first time you call it. The second time you call getLatestGuess() it crashes. Removing the IDs in the XML (e.g. guess1) from all the child views of the RelativeLayout results in no more crashing. Unfortunately now I have a fairly useless RelativeLayout that I can no longer get at the child views of as they do not have IDs. Presumably, IDs are required to be unique.
I think you have to create an root element, and then add the new child.
Like this:
RelatoveLayout root = ....;
RelativeLayout toadd = inflate(your XML);
apply by code change depending of users input, for example:
toadd.setBackgroundResource(....);
and finally add the result to the root :
root.addView(toadd).
I really hope to help you!
Bye!