Dynamically change properties of View objects - android

On my activity's creation I have set an AlphaAnimation in order to perform some visual effects. Now I have set a LayoutAnimationListener and overriden the onAnimationEnd() method. The Animation is executed correctly and the callback to onAnimationEnd() is working as well. Within the onAnimationEnd() method I want to perform another animation on two child objects of the Activity's layout. These are two EditTexts that are defined in XML with the property android:visibility="gone". For starters, what I want to do is to have them set as VISIBLE.
I've tried getting a reference from their parent, change their setVisibility(View.VISIBLE); and in the end invalidate the parent view.
This attempt does not seem to work. You will find the code attached below:
#Override
public void onAnimationEnd(Animation animation) {
Log.d(TAG, "onAnimationEnd()");
// TODO move icon up, make edittext's appear.
RelativeLayout layout = (RelativeLayout) View.inflate(
getApplicationContext(), R.layout.splash_dialog_layout,
null);
LinearLayout linear = (LinearLayout) layout.getChildAt(0);
Log.d(TAG, "Children" + linear.getChildCount());
email = (EditText) linear.findViewById(R.id.splash_Email);
email.setVisibility(View.VISIBLE);
pass = (EditText) linear.findViewById(R.id.splash_password);
pass.setVisibility(View.VISIBLE);
linear.invalidate();
layout.invalidate();
Splash_Activity.layout.invalidate();
}
};
I've tried to removeAllViews from a parent and add them one by one and invalidate again but that doesn't seem to work either.
There is probably a misunderstanding on my behalf as to how view inflation operates, shouldn't this work?
Thanks for your time.

Inflating a layout creates a new view hierarchy, which means the views you're obtaining are actually different from the ones displayed on screen even though they have the same IDs.
You can obtain on-screen views in several ways, but the easiest would probably be to query the containing Activity.
Activity.this.findViewById(R.id.splash_Email);

Related

What does removeAllViews() do with child views?

I have the following hierarchy in my layout:
ScrollView
RadioGroup
RelativeLayout
RadioButton
ImageView
RelativeLayout
RadioButton
ImageView
...
Now the point is, that it looks fine in the XML editor where RadioButtons and ImageViews have default values (placeholders) defined, but when I launch an activity and call removeAllViews() on the RadioGroup, all ImageViews disappear. What's interesting, all buttons get new values, only ImageViews are not updated anyhow (setting new source images gives no results).
So, my question is: does removeAllViews() erase the child views completely (like they never existed in a layout XML file) or just removes some values leaving the views' arguments to be defined (like setting new source image or new button description)?
From the official documentation, removeAllViews():
Call this method to remove all child views from the ViewGroup.
Calling this method will set all the childs view to null, so it will remove the child views from itself, and this child becomes not valid (or not considered as child), but not like it never existed in XML file.
This is removeAllViews() code:
public void removeAllViews() {
removeAllViewsInLayout();
requestLayout();
invalidate();
}
As you can see in removeAllViewsInLayout() method, it set the child value to null:
children[i] = null;

Android - Move a single instance of a View between Parent Views

For an important reason, i'm required to keep only a single instance of a View in the entire application.
Within the application there will be multiple parent views, (each displayed only once at at time). And I need to move the child view around - to the currently active parent.
I tried doing the following:
if (view_to_move_around != null) {
ViewGroup oldParent = (ViewGroup) view_to_move_around.getParent();
if (oldParent != null) {
oldParent.removeView(view_to_move_around);
}
} else {
// Initialise the View
}
newParent.addView(view_to_move_around)
However, that method didn't seem to work? Completely stuck at this point.
I guess my question will be "What do you mean it's not working?" Are you getting an exception? It is not being displayed properly? Does it execute without issue, but is not displaying? Does it display, but it's always initializing?
Are you manipulating the child view within each parent view, before you pass it on to the next view?
Few things to make sure right off the bat:
Layout Params. Are they all set correctly? For both the parent and the child?
Parent View. The code doesn't appear to be faulty from what I can see. So is the parent view being displayed correctly?
Visibility. Are both the parent and child View.VISIBLE?
EDIT
Sweet. Ok, when I'm debugging these things, I like to keep it simple at first. I would take the child view, set it's background color to purple (or a contrasting color from the parent). Then, for simplicity's sake, set it's layout params to match parent. Assuming the ParentView is a FrameLayout:
mChildView.setBackgroundColor(Color.CYAN);
mNewParentView.addView(mChildView,
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT, Gravity.CENTER));
Does it fill up and take over the parent?
In the intermediate steps, does it no longer have a parent when it's been removed?
Log.d("LOGTAG", mChildView.getParent().toString());
Does the new parent show that the child has been added?
Log.d("LOGTAG", mNewParentView.getChildCount()): // before and after
Is it being shown 'behind' the other views within the Parent?
mParentView.bringChildToFront(mChildView);
What may be the problem is that you are using getParent() to store oldParent. Compare for example:
if (view_to_move_around != null) {
ViewGroup oldParent = (ViewGroup) findViewById(R.id.old_parent);
if (view_to_move_around.getParent() == oldParent) {
oldParent.removeView(view_to_move_around);
}
} else {
// Initialise the View
}
newParent.addView(view_to_move_around)
Does this sound like what you're looking for? Let me know if this works.

Adding tags and listeners to the views of a multiple times inflated XML

I am actually developing an android application which needs to inflates many times the same XML layout.
This layout contains 2 buttons, some textViews and a progressBar which I'll need to update later. I would like to add onClick listeners to the buttons and to set custom tags with setTag() to all of these elements, so I will be able to know which button has been clicked and to modify the right textView (or progressBar).
I inflate the XML with this code :
LinearLayout countersList = (LinearLayout)findViewById(R.id.countersLayout);
View child = getLayoutInflater().inflate(R.layout.counter, null);
countersList.addView(child);
How can I access to the right view to set the tag and to add listeners? Is there a better way to do what I want to do ?
Thank you very much !
As far as how to tag or add onClick listeners to your views: You can add an ID to the views you want to tag and find them using findViewById. For example,
LinearLayout countersList = (LinearLayout)findViewById(R.id.countersLayout);
ViewGroup child = (ViewGroup) getLayoutInflater().inflate(R.layout.counter, null);
child.findViewById(R.id.myButton).setTag("myTagForTheButton");
countersList.addView(child);
On the second question, I'm not sure what your UI looks like, but many repeated views might call for using a ListView.
There is no problem of setting tags and listener
LinearLayout countersList = (LinearLayout)findViewById(R.id.countersLayout);
View child = getLayoutInflater().inflate(R.layout.counter, null);
child.setTag("YourString");
// Similarly
view.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
}
});
countersList.addView(child);
If you want it for some of its child you can also do it using findViewById
you can user view.setTag(key, tag) to many tags.
ex:
view.setTag("right_view", rightView);

Duplicate layout IDs returning as -1 after view replacement

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)).

How to properly move a view?

Can someone please explain to a noob the correct way to animate a View so its touch area and image actually move together?!
I have read lots of posts and questions and tutorials, but none explains what moves the layout and what moves the image such that I can animate a view and then leave it at its new position.
This is an example method I'm working with, trying lots of different combinations to no success. The view is in the parent RelativeLayout. It's a touchable menu of icons, and is animated with an xml resource on a click to slide off screen leaving just a little tab showing, where it needs to stay until clicked again.
public void RetractTools (View v){
final ImageView finalImage1 = (ImageView) findViewById(R.id.paintsView);
Animation slideout = AnimationUtils.loadAnimation(this, R.anim.slideout_tools);
slideout.setFillAfter(true);
slideout.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
finalImage1.setEnabled(true);
optionMenu.showing = false;
optionMenu.inMotion = false;
finalImage1.layout(1258, 668, 1697, 752);
finalImage1.setRight(1280);
finalImage1.invalidate();
}
#Override
public void onAnimationRepeat(Animation arg0) {
}
#Override
public void onAnimationStart(Animation arg0) {
finalImage1.setEnabled(false);
}
});
optionMenu.inMotion = true;
v.startAnimation(slideout);
}// End RetractMenu
No matter what I try, I encounter problems. setFillAfter does nothing when set in the xml file. Set programmatically, it leaves the image in the right place but the touch controls remain where the menu was. I have tried setLeft and setRight which apparently only move the image, not the view position, and all sorts of different layout options, and fill and no fill and invalidating and not, but can't solve it. I clearly don't undersatnd the underlying mechanics needed to position and render a view! :D
Thanks.
EDIT : Solution
For anyone having similar issues, this is how I have found to work with relative layouts. You create a LayoutParams object with the specified size, and then you can assign it positions. eg.
final RelativeLayout.LayoutParams position = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
position.leftMargin = 440;
Then assign that to your view
myView.setLayoutParams(position);
So in summary, you use a LayoutParams object as an interface to your view's position, rather than accessing the view's coordinates directly as I assumed.
What you have is basically fine, with two flaws:
You are using setFillAfter(), which is not especially useful
You are calling layout() and setRight() and stuff, which is not especially effective
Instead, in onAnimationEnd(), you need to modify the LayoutParams of the View to reflect the new position you want the widget to be in. The size and position of a widget is dictated by the layout rules it negotiates with its container. Initially, those are set via your layout XML resource. By modifying the LayoutParams at runtime, you are changing what those rules are.
What those LayoutParams are (LinearLayout.LayoutParams, RelativeLayout.LayoutParams, etc.) and what values you should specify in them, we cannot tell you, because we don't know what you are doing.

Categories

Resources