My app for phones has a pager with the main view and the premium features view when swiping right, in landscape mode it has a slightly modified version to fit the landscape orientation.
Now i have to make the tablet UI, and I'd like to show both views on one screen, I've already managed to show them, but the tablet in landscape mode is picking up the fragments from layout-land instead of the portrait layout, and I need it to pick the portrait ones to show side by side.
How can i make the fragment pick the portrait version even if the tablet is in landscape without creating duplicate layouts?
My fragments look like this
public class PremiumFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ViewGroup premiumView = (ViewGroup) inflater.inflate(
R.layout.premium_features, container, false);
return premiumView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d(TAG, "onView created ran");
Intent intent = new Intent("setup");
LocalBroadcastManager.getInstance(getBaseContext()).sendBroadcast(intent);
}
}
It's been a while but for anyone interested in this matter:
If I understand correctly, you need to have a portrait layout, a landscape layout (for mobile for example) and a different landscape layout for tablets which matches the portrait one. There's not that much duplicity involved. You can include an independent non-qualified layout in your qualified layouts.
Lets say you have these layouts:
layout-land/my_fragment.xml
layout-port/my_fragment.xml
layout-large-land/my_fragment.xml
layout/my_fragment_content.xml
layout-port/my_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="#layout/my_fragment_content"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout >
layout-land/my_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
//something completely different
</FrameLayout >
and layout-large-land/my_fragment.xml (contents are the same as portrait one):
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="#layout/my_fragment_content"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout >
There is some minimum duplicity involved but the only important thing is that you have no reason to ever touch layout-port/my_fragment.xml or layout-large-land/my_fragment.xml because all vital information is contained in a single file layout/my_fragment_content.xml.
This topic is more thoroughly analysed in this article that the author probably read aleady:
Android Developers: Building a Flexible UI
Related
[Edited]:
I have already developed one application which works well on different screen size phones and tablets, I followed as per android guidelines to create the different sets of UI layouts to cater with different sizes of screens(phones and tablets) and all layouts will be in portrait mode. Everything works fine till then but now I got one new requirement where the layouts of tablets will be changed i.e. it will be having some extra information than phone layouts and all new layouts will be in landscape mode.
Now my doubts are:
In old implementation, all layouts name are same in different layout folders i.e. layout,layout-small,layout-large etc... so , as per new requirement, all layouts of large and extra-large should be in landscape mode but if i keep the same name of layout then how do I handle the orientation? At present, orientation attribute mentioned in manifest file for each activity.
If I keep the different name of these layouts then I have to handle at run time i.e. while loading the activity,based on checking on phone screen size and then load the respective layout, so same activity can load different layout based on checking screen size. Will it be a optimal approach to do so?
OR,Do I have to altogether introduce new activities for all new layouts to handle this scenario?
Please suggest me best approach to handle this scenario.
A good point to start on this would be official Android documents (below links).
http://developer.android.com/guide/practices/screens_support.html
http://developer.android.com/training/basics/supporting-devices/screens.html
In a nutshell I can tell you would have to create multiple layouts to address your requirement for supporting multiple screen sizes/resolution. Within your application source directory you will have to create a different layout xml (with same name) under different resource-layout-directories as shown below:
res/
layout/ # default (portrait)
main.xml
layout-land/ # landscape
main.xml
layout-large/ # large screen devices (portrait)
main.xml
layout-large-land/ # large screen devices (landscape)
main.xml
I would suggest you to name all similar files with the same name.
Take full advantage of the qualifiers provided by Android like the size, or the set width qualifier. You may have a single pane layout for small screen phones and multi pane layout for tablets. It's a good advice to provide multi pane layout ( you may combine two existing layouts into one ) for landscape orientation.
For example :
res/layout/onepane.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:id="#+id/frag1"
android:layout_height="fill_parent"
android:name="com.example.android.dummyApp"
android:layout_width="match_parent"
android:background="#drawable/bg"/>
</LinearLayout>
res/layout/twopanes.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<fragment android:id="#+id/fragone"
android:layout_height="fill_parent"
android:name="com.example.android.dummyApp"
android:layout_width="400dp"
android:layout_marginRight="10dp"
android:background="#drawable/bg"/>
<fragment android:id="#+id/fragtwo"
android:layout_height="fill_parent"
android:name="com.example.android.dummyApp"
android:layout_width="fill_parent" />
</LinearLayout>
Now that all possible layouts are defined, it's just a matter of mapping the correct layout to each configuration using the configuration qualifiers. You can now do it using the layout alias technique:
res/values/layouts.xml:
<resources>
<item name="main_layout" type="layout">#layout/onepane</item>
<bool name="has_two_panes">false</bool>
</resources>
res/values-sw600dp-land/layouts.xml:
<resources>
<item name="main_layout" type="layout">#layout/twopanes</item>
<bool name="has_two_panes">true</bool>
</resources>
Note : The bool values in the two xml files in values folder.
The Smallest-width qualifier allows you to target screens that have a certain minimum width given in dp. Instead of the large size qualifier, use sw600dp to indicate the two-pane layout is for screens on which the smallest-width is 600 dp.
Also, another solution:
If you are planning to make different activities for different screen sizes, you can build multiple apk for the same project. There should be a separate Android project for each APK you’re going to release.
Please look at this link for more information on Multiple APKs.
http://developer.android.com/training/multiple-apks/screensize.html
Personally, I'd make two different Fragments, with two different Fragment Layouts, and I'd load the Fragment for the right screen size based on the layout folder identifier, like so: http://developer.android.com/training/basics/supporting-devices/screens.html
Typical Fragment:
public class MyFragment extends Fragment implements View.OnClickListener
{
private Button btnSave;
private Button btnCancel;
public MyFragment()
{
super();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_myfragment_small, container, false);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
btnSave = (Button) getActivity().findViewById(R.id.myfragment_small_save);
btnCancel = (Button) getActivity().findViewById(R.id.myfragment_small_cancel);
btnSave.setOnClickListener(this);
btnCancel.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
if (btnSave == v)
{
save();
}
else if (btnCancel == v)
{
cancel();
}
}
}
And do the same thing for the larger one. Bonus points if you reuse the save() and cancel() function by extending from MyFragment, or by ripping out the logic of them into another class.
Static fragment linking:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="#+id/fragment_myfragment_small"
android:name="com.example.stuff.longer.MyFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
And the layout for the fragment in fragment_myfragment_small.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button android:id="#+id/myfragment_small_cancel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="#string/cancel"
/>
<Button android:id="#+id/myfragment_small_save"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/myfragment_small_cancel"
android:text="#string/save"
/>
</RelativeLayout>
And make a second one for the second, larger layout. Place the layout in a different \res\layout folder, such as \res\layout-large.
I tried to create a full screen layout to display a imageview. In the lower end devices (below 4.0) i achieved this, unfortunately when i using the same code in higher end devices the system bar won't be hide. When I used this feature rootView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); (rootView - my fragment view), the system bar is hidden at the moment of application launch, once i touch the screen the system bar is enabled. How can i disable the system bar appearing on user touch until the current activity getting closed?
I think the trick is just to call the native style from Android allowing you to hide the ActionBar by default. Then just select the theme you need to use Holo Light, Holo Dark, etc.).
For example:
public class PhotoDialogFragment extends DialogFragment {
(...)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
//HERE IS THE TRICK
setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Holo_Light_NoActionBar_Fullscreen);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View fullImageView = inflater.inflate(R.layout.photo_fragment, null);
(...)
return fullImageView;
}
(...)
Here is my "photo_fragment" XML file:
<?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" >
<ImageView
android:id="#+id/fullscreen_photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/your_image" />
</LinearLayout>
I'm using Actionbarsherlock and want to use a custom actionbar layout, but still want a navigation list. As a result I am including an IcsSpinner widget. However, the width is always as big as the largest item, and this is not desired. I broke it out of the actionbar to debug and still got the same results:
Fragment Code
public class TestFragment extends SherlockFragment {
private final String[] testStrings = {"Short","Not so long text"};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.test_layout, container, false);
IcsSpinner spinner = (IcsSpinner)view.findViewById(R.id.test_spinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
R.layout.spiner_test_row, R.id.spinner_text, testStrings);
spinner.setAdapter(adapter);
return(view);
}
}
test_layout.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" >
<com.actionbarsherlock.internal.widget.IcsSpinner
android:id="#+id/test_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
R.layout.spinner_test_row
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/spinner_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp" />
Changing to standard Spinner (on gingerbread emulator) works fine:
Any Suggestions?
This appears to be the default behavior of the IcsSpinner component within ActionBarSherlock, even when running Honeycomb+ version of Android - e.g. Square Wallet on my ICS device.
Jake has suggested not using the IcsSpinner component, but without it there is no way simple way to use a custom actionbar layout and maintain the Navigation List UI. Unless Jake can suggest and alternative I will continue to use it, making sure do full testing upon future releases of his great library.
I've been trying to get Roboguice to work with fragments declared in a <fragment> block in the layout file and then injected into the activity, but, although the fragment exists somewhere off screen (an EditText in the fragment takes focus and fires events), It is not visible. Does RoboGuice support what I'm trying to do here or should I go about it a different way?
code:
<?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" >
<fragment
android:id="#+id/myFragment"
android:name="com.example.MyFragment"
android:layout_height="0dp"
android:layout_width="0dp"
android:layout_weight="1" >
<!-- Preview: layout=#layout/my_fragment -->
</fragment>
</LinearLayout>
Java:
#ContentView(R.layout.participant)
public final class Main extends RoboFragmentActivity {
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#InjectFragment(R.id.myFragment) private MyFragment myFragment;
}
Solved the issue, but for anyone else looking - The issue at hand was completely unrelated to RoboGuice, which allows fragment injection exactly as shown above. Rather the issue was that both of my layout dimensions for the fragment were set to 0dp, ensuring that my fragment would never be rendered.
I am using actionbarsherlock library to have action-bar in my application,
I am also using view-pager to switch between the page,
Now the problem is i want only one tab with two fragment to display data regarding each other.
What could be the possible way to do this?
I have been going through like the one below but unsuccessful
In main fragment i am inflating a xml like this
<code>
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragView = inflater.inflate(R.layout.album_view_main, container, false);
return fragView;
}
</code>
xml fie is look like this
<code>
<?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="horizontal" >
<fragment
android:id="#+id/fragment_album_view"
android:layout_width="0px"
android:layout_height="fill_parent"
android:layout_weight="3"
class="com.nix.music.activity.fragments.AlbumFragMent" />
<FrameLayout
android:id="#+id/frame_list_song"
android:layout_width="0px"
android:layout_height="fill_parent"
android:layout_weight="2" >
</FrameLayout>
</LinearLayout>
</code>
but the problem is i cannot find "frame_list_song" in AlbumFragment class it appears null
what could be the way around ?
thank you
This layout should be set in the parent activity using setContentView(). Then, you would be able to do something like getActivity().findViewById(R.id.frame_list_song) from your AlbumFragment. The better way would be to use an interface and transfer control to the main activity, and not access other fragments directly.