My issue is that I have a main screen, and I would like to dynamically spawn a view under it with a button click, then slide the main view off the screen revealing the view below it. I've accomplished this, but I feel like there's got to be a better way. The way I've done it is very limited in that you can't just spawn views over and over again under the main.
My main XML file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<RelativeLayout
android:id="#+id/subpage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
</RelativeLayout>
<RelativeLayout
android:id="#+id/homescreen"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/homebg"
>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
I've deleted some unnecessary stuff. This is what's important. Notice the first child of the main layout is a relative layout with the id "subpage." As it is I use java to inflate another layout into the subpage layout when a button is clicked then I animate the "homescreen" layout off the screen. It seems like I shouldn't have to have the subpage declared in advance though. I guess my question is, is there a way to dynamically declare a new child layout underneath an existing layout?
=======================================================================
Edit: Part 2 of question
I'm trying to use addView and the app crashes. This is the code I use to try to add a view and inflate my xml into it. In the code below subview is a ViewGroup because as I understand it you can only inflate into ViewGroups, not regular views. Also 'activity' is defined at the top of the class as 'private Activity activity = this'. Any ideas what could be causing the crash?
btnHelp.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
subView = (ViewGroup)new View(getApplicationContext());
mainScreen.addView(subView,1);
LayoutInflater inflater = activity.getLayoutInflater();
inflater.inflate(R.layout.help, subView);
}
});
=======================================================================
Edit: Part 3 of question
So one more issue. Everything works great as far as inflating and sliding off. However, the view that is inflated has a button in it. I'm trying to assign a listener to that button, but it doesn't seem to work. I'm doing it by adding the listener to the button after the layout inflater is called in the btnHelp I've been working on. Here's the code:
btnHelp.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
LayoutInflater inflater = activity.getLayoutInflater();
mainScreen.addView(inflater.inflate(R.layout.help, null),0);
homeScrn.startAnimation(slideLeftOut);
btnBackHome = (ImageView)findViewById(R.id.backMenuBtn);
btnBackHome.setOnClickListener(goHome);
}
});
goHome is a handler I've defined below this as such:
private OnClickListener goHome = new OnClickListener(){
public void onClick(View v) {
Log.d("ClickEvent: ","btnBackHome Clicked");
homeScrn.startAnimation(slideRightIn);
}
};
When I click the button referenced by btnBackHome it doesn't do anything. I'm just not sure if it's because the listener isn't actually being assigned, something is keeping the button from actually being clicked, or something else.
Call addView() on the RelativeLayout to add children to it, where the children are either inflated (getLayoutInflater().inflate()) or constructed directly in Java.
Also, you might consider using a ViewFlipper, considering that it does what you're seeking (animated transition from child to child, with only one child visible at a time in the steady state), perhaps with less code.
The default animation when starting a new Activity is a sliding animation.. why not just separate your "homescreen" and "subpage" into 2 different XML files and 2 Activities?
Related
I want to know, there is a linearlayout and use that with setContentView function. Also there is a spinner inside of linearlayout. What I want to do is, create a new layout inside of /res/layout folder and add it into layout that I set with setContentView.
Is there anyway or I need to do that programmatically?
EDIT:
I think I couldn't tell.
I have 2 two layouts(ready). I use the first layout with setContentView.For example, there is a buton and if user click that button, I want to add second layout bottom of first layout when application running.
Easiest you do that with include in the xml of your main layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include layout="#layout/second" />
</LinearLayout>
It´s also possible to do it programmatically, but this way I think it is more clear.
Edit:
To do this programmatically, put this code in listener of the first button.
RelativeLayout view = (RelativeLayout) findViewById(R.id.RelativeLayout1);
Button b = new Button(getApplicationContext());
b.setText("Click me too!");
view.addView(b);
Instead of creating a button (or whatever you want) you can also inflate a premade layout.
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.second, null);
view.addView(v);
I don't think you can change the res folder programmatically. You need to add any layout programmatically only.
Edited:
Get the 2nd layout's instance using findViewById and use setVisibility method to control the layout's visibility.
I have a LinearLayout that contains a TextView, and always will. There will also always be at least one button located below the TextView, but there might be more than one under certain circumstances.
I can successfully create and add as many buttons as I need programmatically. I can also successfully set whatever appearance related parameters/options that I require for these buttons programmatically.
The problem is that I don't know how to tell a programmatically created button that it should use a XML resource file, which contains the appearance and layout parameters, instead of setting these parameters programmatically.
I've looked at similarly named questions and spent time messing with the API itself, to no avail.
Edit:
Here's an approximation of what I'm trying to do that will hopefully make explanations a bit clearer for me:
private TextView textView;
private SomeObject someObject;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View scrollView = inflater.inflate(R.layout.fragment_play_game, container, false);
textView = (TextView) scrollView.findViewById(R.id.game_data_text);
textView.setText(someObject.getTextForTextView());
LinearLayout layout = (LinearLayout) scrollView.findViewById(R.id.game_data_container);
for (String optionText : someObject.getTextForButtons()) {
layout.addView(createOptionButton(optionText, layout));
}
return scrollView;
}
private View createOptionButton(String optionText, LinearLayout layout) {
Button optionButton = new Button(this.getActivity());
// set button layout/options here, somehow??
optionButton.setText(optionText);
return optionButton;
}
My XML layout file for the fragment looks like this (It's this LinearLayout that I'm trying to add buttons to):
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/game_data_container"
etc... >
<TextView
android:id="#+id/game_data_text"
etc... />
</LinearLayout>
</ScrollView>
Also, if I'm to create an XML layout file for the button (lets call it custom_button.xml) should it look something like this?:
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/play_game_option_button"
etc... />
Update:
Just to expand a bit on what MrFox# is talking about, what I did to get it working was replace this line:
Button optionButton = new Button(this.getActivity());
with this one:
Button optionButton = (Button) inflater.inflate(R.layout.play_game_option_button, layout, false);
...which inflates an xml file containing only a Button layout (the button template). In this case, it returns the root view of that file, which is just the button because there's no parent above the button in the file.
However, if I had have set the last boolean value (attachToParent) to true, it would have returned the root container that the button will be in (which is just the 'layout' variable that was passed into the call).
I can now produce as many buttons as I want using this template.
Have you thought of making a layout that is just the button with the applied XML styles and then inflating it into your linear layout?
something like:
inflater.inflate(R.layout.StyledButton, MyLinearLayout, true);
xml for your button under /res/layout/my_button_layout.xml
<Button xmlns:android="http://schemas.android.com/apk/res/android"
... />
code in your activity
myButton = (Button)inflate.inflate(R.layout.my_button_layout, null);
myView.addView(myButton);
I have a very strange problem with Android animations, I tried many different approaches and components, and still couldn't find any explanation.
I have a FrameLayout which is a container for views, and a Button.
This FrameLayout should display only one view at a time, and when I click on the Button, I want the FrameLayout to display another view, and start an animation on the view that is removed from the FrameLayout.
The specificity here is that I only use two views, and I want to switch between these two views.
The problem:
When I click the button multiple times really fast, and then stop clicking, the two views are shown at the same time one on top off the other, and won't disappear. The container still contains only one view though... definitely strange!
error screenshot http://i.minus.com/jDXyvUsE1LCOx.png
I was able to reproduce this with a simple example:
public class TestAnimActivity extends Activity implements OnClickListener {
private FrameLayout container;
private TextView current;
private TextView next;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
current = new TextView(this);
current.setText("View 1 YEAH");
next = new TextView(this);
next.setText(" View 2 DOH");
container = (FrameLayout) findViewById(R.id.container);
container.addView(current);
findViewById(R.id.button).setOnClickListener(this);
}
public void onClick(View v) {
Animation outAnimation = AnimationUtils.loadAnimation(this, android.R.anim.fade_out);
current.startAnimation(outAnimation);
container.addView(next);
container.removeView(current);
TextView temp = current;
current = next;
next = temp;
}
}
As you can see the animations are being started on the views while previous ones are still running, and the way I do that may somehow be the source of the problem.
If I comment the animation related code, it works perfectly:
// Animation outAnimation = AnimationUtils.loadAnimation(this, android.R.anim.fade_out);
// current.startAnimation(outAnimation);
If I stop reusing views and create new views instead, it also works perfectly:
// next = temp;
next = new TextView(this);
next.setText("View: " + new Random().nextInt());
But I don't want to create new views :-) .
It seems that the problem is related to starting animations several times on a view while adding / removing this view from its parent.
I first tried with a ViewFlipper, then a ViewAnimator, then looked up the Android source code and ended up doing this manually to reproduce the problem.
If you want the layout to be able to test by yourself, here is my main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button
android:id="#+id/button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Click me fast" />
</LinearLayout>
Thank you for your time!
I finally found a way to fix the issue.
When we remove a view from a ViewGroup, if there is an animation running on this view, it is automatically added to the "disappearing children" list of the ViewGroup.
The issue seemed to appear when we tried to add to the ViewGroup a view that has been removed from it but was still in its disappearing children.
There's an easy way to fix that : viewGroup.clearDisappearingChildren();
Here would be the new implementation of the onClick() method :
public void onClick(View v) {
next.clearAnimation();
container.clearDisappearingChildren();
Animation outAnimation = AnimationUtils.loadAnimation(this, android.R.anim.fade_out);
current.startAnimation(outAnimation);
container.addView(next);
container.removeView(current);
TextView temp = current;
current = next;
next = temp;
}
If it works without quickly pressing the button, and works without the animation then you may be seeing how animations actually work. From my understanding what is displayed in the animation is separate from the View objects they are animating. You can try animating from the parent view instead of the ones that keep being added and removed. Or make sure to clean up the animation before removing the view, as it sounds like the view isn't able to get the onAnimationEnd method where it can remove the phantom image being displayed (setFillAfter(false) which is the default behavior of an Animation).
want to make an Android app that starts with a main layout and when you push a button (called stateButton) that is in this layout the layout changes to a main2 layout containing another button (called boton2), and when you push this one you get back to the first main.
I want to do this in the same activity without creating or starting another one.
Here I show you part of the code:
public class NuevoshActivity extends Activity
implements SensorEventListener, OnClickListener {
private Button stateButton;
private Button boton2;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.stateButton = (Button) this.findViewById(R.id.boton);
this.boton2 = (Button) this.findViewById(R.id.boton2);
stateButton.setOnClickListener(this);
boton2.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v==stateButton) {
setContentView(R.layout.main2);
}
else if(v==boton2) {
setContentView(R.layout.main);
}
}
}
The mains only have some images, text views and the buttons.
But I've some troubles. Can't it just be as simple as that or what am I missing or what is wrong?
When you use findViewById, you are actually trying to find a view inside the layout you specified by the setContentView. So using setContentView again and again might bring problems when you are trying to check for buttons.
Instead of using a setContentView, I would add the 2 layouts for the screen as child's for a view-flipper which only shows one child at a time. And you can specify the index of which child to show. The benefit of using a view flipper is that you can easily specify a 'in' and 'out' animation for the view if you need an animation when you switch between views. This is a lot cleaner method then recalling setContentView again and again.
The FrameLayout handles this wonderfully... Use this with the <include... contstruct to load multiple other layouts, then you can switch back and forth between them by using setvisibility(View.VISIBLE); and setVisibility(View.INVISIBLE); on the individual layouts.
For example:
Main XML including two other layouts:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:id="#+id/frameLayout1" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android">
<include android:id="#+id/buildinvoice_step1_layout" layout="#layout/buildinvoice_step1" android:layout_width="fill_parent" android:layout_height="fill_parent"></include>
<include android:id="#+id/buildinvoice_step2_layout" android:layout_width="fill_parent" layout="#layout/buildinvoice_step2" android:layout_height="fill_parent"></include>
</FrameLayout>
Code to switch between layouts:
findViewById(R.id.buildinvoice_step1_layout).setVisibility(View.VISIBLE);
findViewById(R.id.buildinvoice_step2_layout).setVisibility(View.INVISIBLE);
You will also need to set the visibility of the individual layouts when the activity starts (or in XML) otherwise you will see them both - one on top of the other.
Your boton2 button will be NULL because the definition of the button is in main2.xml.
The only views you will be able to find are the views which are defined in main.xml.
Thanks!!! All the info was usefull to understand a lot of things and as C0deAttack commented I've got troubles with the button on the main2. What I've done is to set View.VISIBLE and View.GONE to the TextViews and Buttons that I wanted in each layout. Thank you very much.
I want to create the instruction, so when user press the next button I want to set to the
next layout page. I tried setContentView(R.layout.aboutus); but it looks like to set the new
layout to particular page.
Layout:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:background="#dddddd">
<LinearLayout android:gravity="center" android:background = "#drawable/aboutus"
android:orientation="vertical" android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
</LinearLayout>
code :
public void onItemClick(AdapterView<?> parent, View view, int position,
long lg) {
switch (position) {
case 4:
setContentView(R.layout.aboutus);
}
}
So, I want to know how to go to next layout without new activity and can be back to previous page. Thank you.
You should use a ViewFlipper.
Get a reference to the ViewFlipper:
ViewFlipper myViewFlipper = (ViewFlipper) findViewById(R.id.my_viewFlipper);
You then inflate each page as a view:
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.your_layout_id, null);
And then add it to the ViewFlipper:
myViewFlipper.addView( view );
Then when the user hits the button for next page you call this method:
myViewFlipper.showNext();
Or if you want the previous page:
myViewFlipper.showPrevious();
Use a ViewSwitcher or ViewFlipper.
You can try to place the same page in your layout and set all it's component to have Visibility.GONE set, and when you press the button, to set all your visible widgets to GONE and others to Visible. Or you can try a dynamically inflate procedure ( to inflate your views ) since you can use separate layout to inflate views.
Check this for more information about inflate
http://developer.android.com/reference/android/view/LayoutInflater.html
May be you could do this:
If you have two different layouts and one wanna each one at one time.
First get the id's of each layout by findviewbyid method.
then use
firstlayout.setVisibility(View.VISIBLE).
secondlayout.setVisibility(View.GONE);
for showing first layout.
When you press button, in its click listener make
firstlayout.setVisibility(View.GONE).
secondlayout.setVisibility(View.VISIBLE);
it works but the layouts should be seperate.
Hope it helps.