Android - Fragment with two buttons - android

I am working on building an Android application that has a fragment with two buttons, either "News" or "Social". It gets initialised with news, and then if "Social" button is clicked during runtime, it should refresh the fragment with the social's relevant content. Is there a way to do that?

One way to do it is putting two views on the fragment and show/hide properly:
<!-- News -->
<FrameLayout
android:id="#+id/news_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- News content -->
</FrameLayout>
<!-- Social -->
<FrameLayout
android:id="#+id/social_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Social content -->
</FrameLayout>
Then, on Java, you use these containers:
// show news and hide social example
socialContainer.setVisibility(View.GONE)
newsContainer.setVisibility(View.VISIBLE)

Yes you can do it by setting to values of ui elements in on click listener of buttons and pass the respective content of the clicked button. But in case you want to represent information differently then you need to make container layouts and set visibility according to the button clicked.

In your news tab you can achieve the same by following code
newsBtn.setOncliclListener(this);
socialBtn.setOncliclListener(this);
and in your onclick method write down the code for updating your view according to btn click
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.newsbtn:
socailview.setVisibility(View.GONE);
newsview.setVisibilty(View.VISIBLE);
loadYourNewsViewData();
break;
case R.id.socialbtn:
newsview.setVisibilty(View.GONE);
socailview.setVisibility(View.VISIBLE);
loadYourSocialViewData();
break;
}
}

you can use this code in your main activity to load news fragment as first fragment
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="name of your news fragment class"
android:id="#+id/newsFragment"/>

Personally, I would:
Make a container Fragment (just those two buttons of yours), which contains a FrameLayout.
Make a base abstract class of BaseNewsFragment, which is going to be a parent for your NewsFragment and SocialFragment.
Dependent of which button was clicked, I would call a method to replace a content of the FrameLayout with an argument of specific fragment

Related

How to share common layout between activities without fragment

Is there any possible way to share layout(part) between activities? For example, in my app, all activities have similar layout, the top part is long operation indicator (a progress bar, hidden when no operation is being executed), the bottom part is for showing errors. Only the middle part is different for all activities. See the picture below.
so my question is, is it possible to reuse the common layout(loading and error part) for all activities in my app? (currently I don't want to use fragment to do it for some reasons)
maybe the layout resources should like this:
layoutfolder
activity_common.xml
activity_one_content.xml
activity_two_content.xml
thanks
You can create an abstract 'base' activity that all your activities extend from, overriding setContentView to merge the base, and sub activity layouts.
This way you can handle all the loading/error code in the base activity, and simply toggle between hiding and showing the views in the sub activities.
The abstract activity:
public abstract class BaseActivity extends Activity {
protected RelativeLayout fullLayout;
protected FrameLayout subActivityContent;
#Override
public void setContentView(int layoutResID) {
fullLayout = (RelativeLayout) getLayoutInflater().inflate(R.layout.activity_base, null); // The base layout
subActivityContent = (FrameLayout) fullLayout.findViewById(R.id.content_frame); // The frame layout where the activity content is placed.
getLayoutInflater().inflate(layoutResID, subActivityContent, true); // Places the activity layout inside the activity content frame.
super.setContentView(fullLayout); // Sets the content view as the merged layouts.
}
}
the layout file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The main content view -->
<FrameLayout
android:id="#+id/loading_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:id="#+id/error_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
You could use include in XML to, well.. include the re-useable part of your layout code.
As an example, here's my layout file for the Toolbar I used in my app:
// /res/layout/component_toolbar.xml
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:taggr="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/primary"
android:minHeight="?attr/actionBarSize"
taggr:popupTheme="#style/ThemeOverlay.AppCompat.Light"
taggr:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" />
Now, say if I want to use that Toolbar again in a different Activity, this is all I'd have to write:
// /res/layout/whatever_layout_this_might_be.xml
<include layout="#layout/component_toolbar" />
Bear in mind that this would only copy the layout - not the actual behavior of said widget/component.
If you want to actually copy all of the aspects (layout, behaviour) I'm afraid Fragment is the only way to go.
Although ActivityGroup is deprecated fro API 13 but if you don't wish to go with fragments then this can be your best choice.
According to documentation, an ActivityGroup is:
A screen that contains and runs multiple embedded activities.
You can find a tutorial here and here Although the mentioned tutorial uses a Tablayout you can replace that with your common layout in XML.
A second Approach could be Reuse the layout with include tag, in this approach you could just reuse your once created common layout everywhere in the app.

How to create an overlay view within an activity

I have a requirement where i have an activity which shows list of items like facebook feeds and when clicking on a button from one of the list item a dialog has to popup which will show comments for that item.
I was going through the documentation and found out that we have to create a DialogFragment on the fly to achieve this. Please advice if this is the right approach.
You don't actually have to use a Dialog. I think dialogs are more appropriate when you want to show simple views or just an alert/confirmation to the user (normally done with an AlertDialog).
For your situation I guess the best approach would be to have a FrameLayout on your Activity, sibling of your main layout element, and add a Fragment to it when you want to show a popup like that over your main Activity's layout. As long as you put the fragment's view after your activity's root layout element, the fragment will be displayed on top of your main layout, as an overlay. e.g.:
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Activity's main layout here -->
</LinearLayout>
<FrameLayout android:id="#+id/overlay_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</merge>
and then on your Activity when you want to display the fragment you do:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.overlay_fragment_container, yourFragment)
.commit();
Hope it helps :) Luck!

FragmentManager multiple on-screen fragments?

On Android 3.0 and above, the android team is driving hard that you should use fragments over activities. And I see this being useful, but I want to be able to handle click events in my app. I'm using a list fragment on the right side of my app, so doing an onclick (or any click listeners) happens in the activity that hosts the fragment. So I had to move from putting a item in XML to using the fragment manager.
In the design documents they show this picture:
http://developer.android.com/training/basics/fragments/fragment-ui.html
What I want is the Fragment A/B tablet UI. However, nowhere in this page does it actually give you an example of doing this - it seems that fragment manager only works with ONE fragment at a time - which is entirely opposite of what the picture portrays. Which makes me think it uses in XML... but then how would I get an onclick? These documents don't make a lot of sense to me. It shows one thing and then says something else. What if I wanted to remove fragment A on the tablet? Add fragment C that doesn't yet exist? Is that even possible if you tried to use Fragment Manager????
I guess I don't get if Fragment manager uses more than 1 fragment, and if it does, how am I supposed to use this to get an item in the picture like the tablet - the left (A) being a listview, and the right (B) being whatever. Without an ID of the fragment I don't how to access it.
Not sure if this is relevant but here is some of my code:
Adds a fragment to the single framelayout I made like in the guide
//Activity
FragLaunch launchPane = new FragLaunch();
// In case this activity was started with special instructions from an Intent,
// pass the Intent's extras to the fragment as arguments
// firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getFragmentManager().beginTransaction()
.add(R.id.launch_frag_container, launchPane).commit();
}
Also, in portrait mode of 7" tablets, I want it to use a viewpager that is swipeable. It worked like a charm when I designed it in XML but now that I have to access the listfragment it doesn't work (no way to access since I can't have two fragments)
XML of FragLaunch's content view:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:gravity="center_vertical"
android:orientation="vertical" >
<TextView
android:id="#+id/initial_directions"
style="#style/textScalar.Roboto.Light"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/initial_directions"
android:layout_marginBottom="30dp"
tools:context=".Launch" />
</LinearLayout>
I want to have this one appear as Fragment A in the photo:
FragHistory.java/xml for fragment:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/spamhistory"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Spam History" />
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:drawSelectorOnTop="false" />
</LinearLayout>
Does anyone have any insight on this?
If you want your fragments to be able to communicate then you need to use interfaces, like this.
For onClick events you simply set an onClickListener for the view that you need to receive the onClick event from. Like so:
sampleView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Your code here
}
});
As for fragment transactions, it says somewhere in there (I can't remember exactly where) that when two fragments are displayed on the screen at once (as with larger screens) that instead of swapping the fragments it simply updates it. All you have to worry about is making the correct calls. So if you want to remove fragment A just call remove(). Or if you want to replace it with fragment C call replace() and pass fragment C in as the parameter.
Can you clarify your question about the ViewPager? What do you mean "have to access it"?
Hope this helps!
EDIT: I apoplogize, I misunderstood your question. Here's kind of a quick run down of how to add more than one fragment to the screen at once.
1. Perform a runtime check to make sure that the device screen is big enough to display more than one fragment.
2. If the screen is big enough, set the content view to use a layout that has a FrameLayout for each fragment that you want to add.
3. After that grab a reference to each fragment that you want to use.
4. Then use the FragmentManager to add a fragment to each layout. Like this:
FirstExampleFragment fragment1 = new FirstExampleFragment();
SecondExampleFragment fragment2 = new SecondExampleFragment();
getSupportFragmentManager().beginTransaction().add(R.id.example_framelayout1, fragment1)
.add(R.id.example_framelayout2, fragment2).commit();
Another great way to allow communication between fragments is to use an event bus, such as the Otto event bus. Otto allows components to publish events and subscribe to events in a decoupled manner.
In your particular case, when a user selects an item in the list, your list fragment can publish an event (which can include the item that has been selected) and your content fragment can subscribe for these events and update its content accordingly when it receives a new event. This all being done without the two fragments being directly coupled and without having to define additional interfaces.
I know this doesn't answer your entire question, but thought it might be useful when it comes to the communications between your fragments....YMMV.

Replacing a ListFragment shows the previous list on top of the new one

I have a ListFragment in one of my views, I make a selection in the list and and I replace that fragment with another list. I then again make another selection in this list that replaces this list with another list but that third list always shows on top of the original list like it was never replaced, why would this happen, can I not go three levels deep when replacing fragments?
here is the layout of the view
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<fragment
android:id="#+id/frameOne"
android:name="com.tyczj.bowling.BowlersListFragment"
android:layout_width="300dp"
android:layout_height="match_parent"
android:background="#drawable/list_background_holo" />
<fragment android:name="com.tyczj.bowling.BowlerEntryFrag"
android:id="#+id/frameTwo"
android:layout_height="match_parent"
android:layout_width="fill_parent"/>
</LinearLayout>
frameOne is the fragment that always gets replaced
an Item in the list is selected and I call to replace the list with a new one
ft.replace(R.id.frameOne, infoLf).addToBackStack(null).commit();
then another selection is made in that list so I replace it again like so
ListFragment mBowlersBall = new BowlersBallList(bowlerID);
ft.replace(R.id.frameOne, mBowlersBall);
ft.addToBackStack(null).commit();
and that is when it shows the two lists together like this
You aren't properly replacing the fragments.
First of all the documentation for the FragmentTransaction.replace() method is pretty clear and it states that the id supplied to it should be the id of the the container whose fragment(s) are to be replaced and not the id of the Fragment to be replaced like you do.
Second, you're mixing static fragments(declared in the xml layout) with dynamic ones(which are added at runtime), which you shouldn't be doing. If you're going to replace that Fragment you'll need to declare that Fragment in code and not in the xml layout(see this response from one of the Android engineers regarding this matter).
So, instead of the frameOne Fragment insert a wrapper layout(like a FrameLayout for example) with an id. In the onCreate method you'll add your initial Fragment(BowlersListFragment) and then, based on a selection in that Fragment, you'll replace it by giving to the FragmentTransaction.replace() method the id of the wrapper layout and the new Fragment instance.

Complex Android UI design guidance needed (fragments)

I am developing an applications that is aimed at Tablets and Google TVs. It will be like many standard Google TV applications with a LeftNavBar and a top Search bar that is common to all application screens. It will look something like the following image:
Main Screen
The RED area will be different for all other screens. It may contain data like following screens mockups:
Activity One loaded into main container
Activity Two loaded into main container
So you can see that completely different sections can be loaded in the main area.
Screen 3 can be loaded as a detailed section when selecting any list item in Screen 2 (say in fragment list) OR it can be loaded as a result of selecting a tab (which will appear in LeftNavBar).
Here is how I am trying to implement it.
Step 1. I Created a main Activity with the following XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#9ccc" >
<!-- Top Bar -->
</LinearLayout>
<FrameLayout
android:id="#+id/mainContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<!-- main Red Container that will load other Activities -->
</FrameLayout>
</LinearLayout>
mainContainer is the RED container where I want to load the Activities. LeftNavBar will be added to this Activity as its the parent of All.
Step 2 I created ActivityOne & ActivityTwo with two & three Fragments in them respectively (as shown in above second & third image).
*Step 3 I am trying to load the ActivityOne in main page's mainContainer FrameLayout... But I cannot add it.
I tried by adding the ActivityOne to mainContainer as follows:
View v = (new ActivityOne()).getWindow().getDecorView();
FrameLayout mainContainer = (FrameLayout) findViewById(R.id.mainContainer);
mainContainer.addView(v);
but the getWindow() returns null....
Other issue occurs because all the data comes from a remote services .. so please also suggest how would I be able to hold references to all the loaded Activities in mainContainer in a some kind of stack ... so I can just reload the already loaded activity instead of creating its new instance.. This will be used on BACK button press.
OR
Instead of loading an activity into the above RED container, I should create two Activities each with their own Fragments & a LeftNavBar. This might be easier than the aforementioned approach. or this might be the only solution.... however I feel that saving state for BACK buttons might get messy .. but I will try implementing this
What would you do if you had to create this type of application?
How would you design the UI layout for best performance/practice?
Your suggestions in helping me setting this app's layout are much appreciated.
Disclaimer
This is where fragments can get tricky. The problem would be simple if Activity 1 & 2 had identical layouts so that you could simply attach/detach fragments and use the fragment back stack to unwind.
Because you want 2 unique layouts to house your fragments, things are going to be a little more involved. If at all possible I would try to use the same layout so that you can take the easy path.
As another option, you could use two activities as you outline above and send data back and forth with Intents.
That said, if I really had to implement this solution as written, here is what I would do. Note that I am not advocating this solution but myself do not know of a better way of doing things.
The Solution
Create a FragmentActivity whose view would be Main Screen as you've defined above. The layout for the Main Screen would contain:
Left nav bar
Top bar
2 layouts. layout1 and layout2. These would be contained in a parent layout i.e. RelativeLayout or LinearLayout and would contain the necessary FrameLayout elements for your fragments.
Example using your XML (note, tags are a bit brief):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#9ccc" >
<!-- Top Bar -->
</LinearLayout>
<LinearLayout android:id="#+id/layout1">
<FrameLayout android:id="#+id/listFragment" />
<FrameLayout android:id="#+id/contentFragment" />
</LinearLayout>
<LinearLayout android:id="#+id/layout2">
<FrameLayout android:id="#+id/imageFragment" />
<FrameLayout android:id="#+id/boxFragment1" />
<FrameLayout android:id="#+id/boxFragment2" />
<FrameLayout android:id="#+id/boxFragment3" />
</LinearLayout>
</LinearLayout>
The main idea is that you then show/hide layout1 & layout2 i.e. set android:visibility="gone" based on the state of your app.
The disadvantages of this method are:
Using fragment backstack may be impossible, instead you'll have to track where the user is in your UI flow and manage the back button to show/hide layout
You may need to take special care to attach/detach fragments when you show/hide their parent view to reduce resource consumption while the fragments are invisible
The advantages are:
Easy communication between fragments and the base activity since only 1 activity is used
Re: The nested Fragments problem
To get around the 'nested Fragments' problem in our application where (as you correctly note) Fragments cannot add Fragments I hosted a single templating Fragment under the activity whose only purpose was to define a set of place holders for other fragments to anchor to. When adding further Fragments to the activity past this point I used the templating Fragment's view place holder +#ids to identify the "root" or parent view Id for the Fragment being added.
getSupportFragmentManager().beginTransaction().add(#someIdFromTheTemplateFrag, fragment, fragmentTag).commit();
The Fragment I was adding then knew where to anchor itself in the current layout and of course then went about it's merry way of add it's view. This had the effect of attaching a Fragment to another Fragment hence achieving the desired visual 'nesting'...

Categories

Resources