I'm going mad soon, been reading Google search results for 10+ hours soon, without any luck.
I think i will drop this whole idea of using a spinner and just use tabs, but it still irritates me that i haven't found a solution. So i hope anyone could help me to understand this issue.
The project im creating has one MainActivityContainer (the main FrameLayout), and than multiple fragments (different layouts) that gets first added and than replaced inside the MainActivityContainer.
So the app only opens ONE activity and than changes pages through different fragments. This makes it super fast to change pages.
Everything except for the ActionBar Spinner works great. It doesnt get updated when pressing the back button, i.e it is still displaying the value for the last fragment.
I want to use the spinner so i easily can navigate between different fragments.
The app start page look something like this:
http://1drv.ms/1jkJpy2
The spinner items are:
1. home , 2. ImageBtn1, 3. ImageBtn2, etc.
So i can reach each destination by either clicking the image button or using the spinner. This is the functionality that i want.
But if i click imagebutton (instead of using the spinner) the value in the spinner (home) does not change to ImageBtn1. So even though i am on the page for ImageBtn1 the spinner shows "Home".
I fixed this by using actionBar.setSelectedNavigationItem(1); in the method for the ImageButton. So imagebuttons uses the spinners methods manually. This sets the spinner to the correct value even if pressing the imagebutton on the start page.
This all works well until i press the back button. Than i have the same problem again, the spinners value doesnt update.
So please explain to me how i can solve this. In other words: How to use a spinner actionbar with ONE activity and many fragments and still get the back button to update the spinner. I have began experimenting with the onBackPressed() method. But there has to be an easier way to achieve what i want to do???
Ok I figured out how to update the navigation spinner in the action bar!
In my problem, I always called actionBar.setSelectedNavigationItem(int); inside the onCreate() method of the activity. However, onCreate() is only called when first making a new activity. So whenever I pressed the back button, the onCreate() doesnt get called and the navigation spinner doesn't get updated. However, the onResume() function always gets called when an activity becomes visible to the user (whether the activity was just created or whether the user pressed the back button into it). So I simply called actionBar.setSelectedNavigationItem(int) in onResume() and the navigation spinner now updates whenever the user presses back!.
However, since you are using one activity with multiple fragments, you should probably put your actionBar.setSelectedNavigationItem(int) inside the onResume() of your fragments instead of the activity. And that should work!
I guess this is a good case for really learning and internalising the activity and fragment lifecycles. Back to more learning for me :).
I was wondering if you managed to find a solution? I have a similar problem to you.
In the activity, inside the onBackPressed() method, try calling getSupportFragmentManager().findFragmentByTag(TAG); where TAG is a string that you can give when adding each of the frames (have a different TAG for each fragment).
So in code, when you are putting the fragment in:
getSupportFragmentManager().beginTransaction().add(R.id...., new MyFragment(), "TAG1");
Then the onBackPressed method would look like:
#Override
public void onBackPressed() {
MyFragment myFragment = (MyFragment)getSupportFragmentManager().findFragmentByTag("TAG1");
if (myFragment.isVisible()) {
getActionBar().setSelectedNavigationItem(int);
}
}
Let me know if that works!
NEVER use NAVIGATION_MODE_LIST and onNavigationItemSelected it is not worth it !
#Override
public boolean onNavigationItemSelected(int position, long itemId)
You also cannot use menu's to do this:
#Override public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.activity_main, menu);
due to inflation ordering.
Reasons:
(1) it generates a "hidden" spinner, for which you can not get the id.
(2) you cannot customize this spinner
(3) you save 30 lines of code, but are permanently limited if you want to add a second bi-directional spinner
(4) not even in the special case of "simple code" (one spinner), you lose to much.
(5) you cannot use tabs.
(6) without the id, you have no chance with fragments.
the key is actionBar.setCustomView(R.layout.action_bar_custom);
and spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()...
for each spinner.
Trust me I lost hours trying each solution.
Related
I am currently writing a drawer layout as my main layout, with an embedded FrameLayout that I will be using to hold each “page” when an item on the drawer is clicked on. When the app first starts, an initial fragment will be show. Other fragments may be added/replaced later which is fine, however, my problem is that when the user clicks the back button on the very first “initial fragment”, I don’t want that particular fragment to be removed from the layout. Currently, it is being removed and it’s just showing a drawer layout with no other content (which makes sense). I want the app to automatically exit if the initial fragment was the last one showing and the back button is pressed, instead of removing that initial fragment and then after another back press, then it exits.
Things I have thought of doing:
Not adding the first fragment to the backstack. (If I do this, I can compare it with the classname of the fragment which is a somewhat longer string, or I can use a boolean value for once the first fragment has been placed (and not added to backstack), the boolean is set which allows the fragments to now be added.
Overriding the onBackPressed function of the activity
Does anyone have a suggested way of doing this or can think of a better way? Thanks
The first bullet point sounds the cleanest. You have no other need to handle conditions when back is hit, correct? If that's the case, it's less lines of code (removing one as opposed to adding several) and you get to keep default Activity methods as is.
I know that's not exactly what you asked, but I think the first bullet point is so clean, that I just wouldn't try something else.
I have implemented same in one of the app using my own Stack of fragment. and also implemented onBackPressed method.
Every time when user clicks on item in drawer i add fragment in stack and in back press once its length is 1 I finish the activity with message.
On item click -- Add/replace fragment in container.
OnBackPressed -- Pop fragments from stack and once its last one i finish activity.
Hope this can give you another option to consider.
I have been following the Udacity's android app development course.
Sometimes they add the onOptionsItemSelected() method inside the fragment and sometimes they add it inside the parent activity.
I am a beginner to android development.
Can someone clarify that when are we supposed to add the onOptionsItemSelected() method inside the fragment and when inside the activity which contains the fragment ?
Also, it would be great if someone could give an intuitive explanation of a Fragment (how is it bound to the parent activity inside which it is present)
In android option menus can be added to both Activity and Fragment. So that Activity and Fragments can have their own option menu's and their own callbacks..
To your first question. A fragment represents a specific portion of your application, so if it's important to have a new menu item present while this portion is visible, you handle the item in the fragment. If a menu item should always be accessible you manage this item in the activity.
Not sure if I got your second question, but I try to answer anyway. First of all the developer side concerning fragments is pretty long but pretty good too.
You can a reference of parent activity in a fragment by calling getActivity. That gives you the ability to make public calls like findViewById.
I am developing an Android application and I have the standard list and details implemented with fragments. In case that only one pane is shown, I want to dynamically set the action bar title after transition depending on the selected item. Where should I do that?
I have already put the index of the selected item in the intent and forwarded it to the fragment, so both detail activity and detail fragment know about it. Logically, I would set the title in the fragment, otherwise I have to deal with my content in the activity. However, I also have to check whether I am in one or two pane mode which is done in the activity. So, where is the right place for updating the title?
For me, updating the title (and everything related to the content) belongs to the fragment. I was first thinking about using an interface for invoking an updateTitle method of the fragment from the activity. Because of the high complexity for such a simple thing, I rejected the idea. Instead, I check in the fragment whether a detail fragment is displayed, in order to know whether there are one or two panes on the screen. After that, I simply invoke getActivity().setTitle(title) from the fragment with my title as parameter. This seems to be much shorter.
I would still appreciate each answer telling me what is the best practice in respect to this. But for now, my problem is solved.
This question is actually a 3 Part Question. Please suggest the valid solution for my problem.
Application Overview
I'm creating an application having a splash screen and a ListView. On click of the launcher icon, first the splash screen is shown and then after 3-4 seconds later, the splash screen calls the ListView activity and user is left with ListView items on the phone screen. On click of each item, respective textual content will be visible to the user. After reading the content user will click the "Back" button and will be returned to hte ListView items section again. If he/she wants to read any other item content, will be taken to that page on the click of that item. If not willing, then will click "Back" button on phone and application will close.
Part 1 - What I actually want to do
I want to show different textual content (not normal text but styled (bold/italized/containing images and all) on the click of different listView items. I can create the html pages and store them in my resource folder locally but don't know how to call those pages while calling onItemClickListener. I'm not sure if this is a valid approach to do this sort of work or not. Please advice. It's not working so far
Part 2 - What I'm doing instead now
Since I was not able to call the textual content so I wrote the content on some text editor, did all the fancy work on the editor and when the content was ready, I took the screenshot and then call that image instead while calling onItemClickListener. It's working fine and I'm able to see the image on click of my ListView item.
Part 3 - The problem I'm facing
When the image is shown to the user, on click of "Back" button, the application is closed instead of going back to the ListView Section. Apparently the image opening on click of the listview item is in the same activity as is the ListView itself. What I want is that user should be able to go back to the ListView section after he/she finishes reading the textual content.
Below is the code of the ListView Activity:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView) findViewById(R.id.menulist);
String[] values = new String[] { "1. First Article Here", "2. Second Article Here", "3. Third Article Here"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
R.layout.custom_listview, R.id.text1, values);
// Assign adapter to ListView
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, android.view.View view, int position, long id){
//
if(0==position)
{
setContentView(R.layout.image0);
}
else if (1==position)
{
}
}
});
}
*The code works fine upto setContentView(R.layout.image0);
* But after this I want the application to return back to the ListView section on click of "Back" button but it closes instead. Please guide.
May be it solves by,
Using layout.image0 in another activity and call by intent when click on list item.
By use this, When you click back button you view your previous activity
When you press the back button, the current activity get closed and you get back to the previous activity on the stack. Given that you are not changing activity by pressing the list element, but only changing the layout, pressing the back button empties the stack and closes your app.
The cleanest way would be to launch the splash screen in another activity.
A couple of other ways to solve it are:
- add a stack of fragments
or (the dirtiest way), override the onBackPressed(), intercept it when your app is showing the splash screen and change back the layout to the listview.
I would prefer the other approaches.
If you use setContentView() method, the back button functionality will not work, since no new Activity was created, from which you can go back to the listView. I'd rather take the clicked item's useful information, put it in an Intent (link), and call startActivity() method, to start a new activity, to show content to the user. Then, if the user clicks the back button, the "details" activity will disappear, and the user again sees the listView.
You are using setContentView so its overriding the current view with ur new View in OnItem Click...Rather add a View Group to ur activity like a Relative layout...And when u click your Itme add a new layout to ur existing layout and on back remove the layout.
Or u can Use DialogView to dynamically add a view ..see below:
Dialog dialog = new Dialog(this, android.R.style.Theme_Dialog);
dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, 0xff000000);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(Your VIew);
dialog.show();
Or at last you can start Another Intent using your current Activity..
Part 1 and 2
You can create complex and styled layouts using the XML files.
If you really want to use HTML, I advice you to use a WebView. You can store the plain html-string somewhere in your resources and use Webview.loadDataWithBaseUrl() to show it in your WebView.
You can make your choice depending on your functionality. If you have alot of different events to be handled (like clicking on a View), I would opt for the XML files. Because you can assign different listeners to seperate Views. When your functionality doesn't go further as it does now, only clicking a whole view. You can use a WebView as well.
Part 3
The problem is that you are abusing the setContentView-method. setContentView tells Activity which XML file it has to use. In your case, when the Activity is created, it will use R.layout.activity_main.
When you click your item, you tell the Activity.. Don't use the R.layout.activity_main anymore, but use R.layout.image0. The Activity will do this and your image will be shown.
This is not a good way to change layout though and will mess up your working flow. The reason that, when the image is shown, your application closes on Back is that there is only 1 Activity started. (Your stack contains only 1 Activity) You just switched the layout, but no new Activity is started.
Solution
Create 2 Activities:
Create a main Activity showing the your list and set the layout with setContentView(R.layout.activity_main). When your click-event is triggered, you will start the second Activity. Intent i = new Intent(...). You can also add some arguments to the Intent and access them in your second Activity to know which item was clicked and which image to show.
A detail Activity showing your content or in your case an Image. setContentView(R.layout.image0).
Solution 2
Create a popup to show your content. You can use a Dialog for that.
I am having an issue here that is driving me nuts. What I have is the following:
FragmentActivity1 holds the viewPager. It instantiates the FragmentAdapter and two fragments and attach them to the ViewPager.
Fragment1 has only one button. When user clicks this button, I create one Intent and invoke a FragmentActivty. This fragmentActivity contains a form, which the user fills in and press OK. When he does that, I persist the data in the DB of the app.
Fragment2 is a ListFragment, and lists all the data that was inserted previously by the user.
By the time user completes the form and presses OK, I persist the data, like I said and finish() the activity, returning to Fragment1. WHen I swype to Fragment2, the data is not there. I need then to swype to Frag1 and then back to Frag2. Only then I can see the problem.
I have tried setting listeners between activities and fragments but, still, cant make this work.
Have anyone seen? I am willing to share my small project as well, so you guys can take a look.
Thanks,
Felipe
I usually fill my ListView in onResume() in the ListFragment. When I'm done adding new stuff to the list (In a seperate FragmentActivity, just like you), the ListView automatically gets refreshed, because onResume() gets called ;)
Another approach is using onActivityResult(), then you can update list only when something new is added or something is removed