I have an app that currently works on a handheld device and I now want it to work on a tablet using a master/detail flow. I have an InformationFragment that is shown when you click on an item in a ListView. The app works on a handheld device, but on a tablet I get an exception that there is no view found for two_pane_information_container. Here is my code:
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
twoPane = getResources().getBoolean(R.bool.isTablet);
setContentView(R.layout.main_layout);
// setting up the navigation view and listfragment etc.
}
public static class InformationListFragment extends ListFragment {
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Info o = (Info) getListAdapter().getItem(position);
Bundle b = new Bundle();
b.putParcelable("info", o);
if (twoPane) {
// load the fragment to the right of the list
// this is the part causing problems
android.support.v4.app.FragmentTransaction ft =getFragmentManager().beginTransaction();
InformationFragment ia = new InformationFragment();
ia.setArguments(b);
ft.replace(R.id.two_pane_information_container, ia);
ft.commit();
} else {
// An activity that displays the inforrmationfragment
// this works
Intent i = new Intent(getActivity(), InformationActivity.class);
i.putExtra("info", b);
startActivity(i);
}
}
}
res/layout/fragment_main.xml
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/table_background" >
<!-- The main content view -->
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v4.view.ViewPager>
<!-- The navigation drawer -->
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#android:color/background_dark"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="1dip" />
</android.support.v4.widget.DrawerLayout>
res/layout/main_twopane.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="horizontal" >
<include
android:layout_width="400dp"
layout="#layout/fragment_main" />
<LinearLayout
android:id="#+id/two_pane_information_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
</LinearLayout>
</LinearLayout>
res/values/layouts.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="isTablet">false</bool>
<item name="main_layout" type="layout">#layout/fragment_main</item>
</resources>
res/values-large/layouts.xml and res/values-sw600dp/layouts.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="isTablet">true</bool>
<item name="main" type="layout">#layout/main_twopane</item>
</resources>
Your layout name in the final 2 XML files differs.
<item name="main" type="layout">
should be
<item name="main_layout" type="layout">
Related
I am trying to implement a settings view invoked from a drawer menu.
Settings view is implemented using a Fragment inheriting from MvxPreferenceFragmentCompat. Code is below:
[MvxFragmentPresentation(typeof(MainViewModel), Resource.Id.main_content_frame)]
[Register(nameof(SettingsFragment))]
public class SettingsFragment : MvxPreferenceFragmentCompat<SettingsViewModel>
{
public override void OnCreatePreferences(Bundle savedInstanceState, string rootKey)
{
SetPreferencesFromResource(Resource.Xml.preferences, rootKey);
}
}
My preferences.xml is shown below:
<?xml version="1.0" encoding="utf-8" ?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="#string/pref_debug_info_title"
android:key="pref_key_debug_info">
<CheckBoxPreference
android:key="pref_key_provide_debug_info"
android:title="#string/pref_title_provide_debug_info"
android:summary="#string/pref_summary_provide_debug_info"
android:defaultValue="false" />
<CheckBoxPreference
android:key="pref_key_provide_debug_info_over_wifi"
android:title="#string/pref_title_debug_info_over_wifi"
android:summary="#string/pref_summary_debug_info_over_wifi"
android:defaultValue="true" />
</PreferenceCategory>
</PreferenceScreen>
Fragment layout is below:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="#+id/fragment_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="#layout/include_toolbar_actionbar_addlistitem" />
<fragment
android:name="SettingsFragment"
android:id="#+id/settings_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<include
layout="#layout/include_floatingactionbutton" />
</android.support.design.widget.CoordinatorLayout>
And finally, main activity XML is here:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="true">
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_content_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true" />
<FrameLayout
android:id="#+id/navigation_frame"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="left|start" />
</android.support.v4.widget.DrawerLayout>
My preferences show up fine but I don't see the AppBar with a title (that I could set) and there is no arrow to navigate back to the Activity. When I press the back "hardware button" once, nothing happens. When I press it the second time, the app "minimizes" and when I bring it back, I am back at the main activity.
I have done this functionality with "regular" Fragments inheriting from MvxFragment but it seems like I am unable to do so with MvxPreferenceFragmentCompat.
Update 1
Based on input from Trevor, I have update fragment_settings.xml and SettingsFragment.cs as shown below:
fragment_settings.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="#+id/fragment_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="#layout/include_toolbar_actionbar" />
<!-- Required ViewGroup for PreferenceFragmentCompat -->
<FrameLayout
android:id="#android:id/list_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
local:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<include
layout="#layout/include_floatingactionbutton" />
</android.support.design.widget.CoordinatorLayout>
SettingsFragment.cs
[MvxFragmentPresentation(typeof(MainViewModel), Resource.Id.main_content_frame)]
[Register(nameof(SettingsFragment))]
public class SettingsFragment : MvxPreferenceFragmentCompat<SettingsViewModel>, View.IOnClickListener
{
#region properties
protected Toolbar Toolbar { get; set; }
protected AppCompatActivity ParentActivity { get; set; }
#endregion
#region Fragment lifecycle overrides
public override void OnCreatePreferences(Bundle savedInstanceState, string rootKey)
{
AddPreferencesFromResource(Resource.Xml.preferences);
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = base.OnCreateView(inflater, container, savedInstanceState);
ParentActivity = ((MainActivity)Activity);
Toolbar = view.FindViewById<Toolbar>(Resource.Id.main_tool_bar);
ParentActivity.SetSupportActionBar(Toolbar);
ParentActivity.SupportActionBar.SetDisplayHomeAsUpEnabled(true);
ParentActivity.SupportActionBar.SetDisplayShowHomeEnabled(true);
...
// TODO: Pull it from a resource
Toolbar.Title = Resources.GetText(Resource.String.settings_view_title);
return view;
}
#endregion
#region View.IOnClickListener implementation
public void OnClick(View v)
{
ParentActivity.OnBackPressed();
}
#endregion
}
But I am still getting null on line ParentActivity.SupportActionBar.SetDisplayHomeAsUpEnabled(true) because my SupportActionBar is null (but Toolbar is not). How come?
Update 2
OK, I got a bit further. I got my AppBar and arrow back and the look and feel is like I have expected it. Still have a problem but more about it below.
What helped? This post.
In short, I needed to declare a custom style for my preference and in it, reference the layout of my preference view. Here are the bit:
Styles.xml
<style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
...
<item name="preferenceTheme">#style/AppTheme.Preference</item>
</style>
<!-- Custom Preference Theme -->
<style name="AppTheme.Preference"
parent="#style/PreferenceThemeOverlay.v14.Material">
<item name="preferenceFragmentCompatStyle">
#style/AppPreferenceFragmentCompatStyle
</item>
</style>
<!-- Custom Style for PreferenceFragmentCompat -->
<style name="AppPreferenceFragmentCompatStyle"
parent="#style/PreferenceFragment.Material">
<item name="android:layout">#layout/fragment_settings</item>
</style>
For me, this has been the missing link between the view declaration in the SettingsFragment and the layout resource.
The only problem that remains is ability to go back from this fragment back to main activity. From a "regular" MvxFragment (that is invoked from a drawer), I use OnClick method of the IOnClickListener to call ParentActivity.OnBackPressed().
SettingsFragment.cs
public class SettingsFragment : MvxPreferenceFragmentCompat<SettingsViewModel>, View.IOnClickListener
{
...
public void OnClick(View v)
{
ParentActivity.OnBackPressed();
}
}
But this does not work from this MvxPreferenceFragmentCompat. Still searching for that answer.
Update 3
Last missing piece of the puzzle was the AddToBackStack declaration atop the class as shown below. Once this was in place, OnBackPressed() worked correctly.
SettingsFragment.cs
[MvxFragmentPresentation(typeof(MainViewModel), Resource.Id.main_content_frame, AddToBackStack = true)]
[Register(nameof(SettingsFragment))]
public class SettingsFragment : MvxPreferenceFragmentCompat<SettingsViewModel>, View.IOnClickListener
You're missing some code to setup the AppCompatActivity.SupportActionBar like you would in any other fragment. Here is how I've solved the problem:
Here is the SettingsFragment Layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/coordinator"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
tools:context=".Activities.MainActivity">
<include
layout="#layout/toolbar_actionbar" />
<!-- Required ViewGroup for PreferenceFragmentCompat -->
<FrameLayout
android:id="#android:id/list_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
Here is the SettingsFragment implementation:
public class SettingsFragment : MvxPreferenceFragmentCompat<SettingsViewModel>,
View.IOnClickListener
{
private Toolbar _toolbar;
private View _view;
private MainActivity MainActivity => (MainActivity)Activity;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Since the view is created in PreferenceFragmentCompat's OnCreateView we don't use BindingInflate like a typical MvxFragment.
_view = base.OnCreateView(inflater, container, savedInstanceState);
// TODO: Setup MvvmCross Databinding manually since we didn't use BindingInflate like a typical MvxFragment.
_toolbar = _view.FindViewById<Toolbar>(Resource.Id.toolbar);
if (_toolbar != null)
{
MainActivity.SetSupportActionBar(_toolbar);
MainActivity.SupportActionBar.SetDisplayHomeAsUpEnabled(true);
MainActivity.SupportActionBar.SetDisplayShowHomeEnabled(true);
_toolbar.SetNavigationOnClickListener(this);
// TODO: Bind the Toolbar.Title
}
return _view;
}
public override void OnCreatePreferences(Bundle savedInstanceState, string rootKey)
{
AddPreferencesFromResource(Resource.Xml.preferences);
}
public async void OnClick(View v)
{
// Toolbar was clicked
await ViewModel.CloseCommand.ExecuteAsync().ConfigureAwait(false);
}
}
I'm using StarWarsEaxmple from MvvmCross repository and I can't make it work. The output of MvvmCross ,The problem in my opinion is either in different versions of MvvmCross or in Presenter. In Samples version is 5.1.1 and in my project is 5.4.2. And demonstrates weird behavior.
I can see empty drawer when I don't involve MvvmCross NavigationService. However, when I navigating to both ViewModels sequently (as in the example) I can see only Menu Page without drawer and other page frame is even doesn't invoked.
Reference to MvvmCross Sample
Main Activity
[Activity(Icon = "#drawable/icon",
Theme = "#style/AppTheme", LaunchMode = LaunchMode.SingleTop,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : MvxCachingFragmentCompatActivity<MainViewModel>
{
public DrawerLayout DrawerLayout;
//This method is invoked
protected override void OnCreate(Bundle bundle)
{ base.OnCreate(bundle);
SetContentView(Resource.Layout.activity_main);
DrawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawerLayout);
ViewModel.ShowDefaultMenuItem();
}
....
Menu Fragment
[MvxFragment(typeof(MainViewModel), Resource.Id.navigationFrame)]
[Register("VacationManager.Droid.Activities.MenuFragment")]
public class MenuFragment : MvxFragment<MenuViewModel>, NavigationView.IOnNavigationItemSelectedListener
{
private NavigationView _navigationView;
private IMenuItem _previousMenuItem;
//This method is invoked too
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
var view = this.BindingInflate(Resource.Layout.menu_view, null);
_navigationView = view.FindViewById<NavigationView>(Resource.Id.navigation_view);
_navigationView.SetNavigationItemSelectedListener(this);
return view;
}
}
Main Part of Page
[MvxFragment(typeof(MainViewModel), Resource.Id.bodyFrame, false)]
[Register("VacationManager.Droid.Activities.VacationRequestListFragment")]
public class VacationRequestListFragment : BaseFragment<VacationRequestListViewModel> // You can find BaseFragment in sample
{
protected override int FragmentId => Resource.Layout.fragment_list;
//It is never invoked
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
return this.BindingInflate(Resource.Layout.fragment_list, container, false);
}
}
MainPage Layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/warning">
<!-- Center Side -->
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/mainFrame">
<include layout="#layout/toolbar" />
<FrameLayout
android:id="#+id/bodyFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"/>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"
android:src="#drawable/bullseye"
local:layout_anchor="#id/bodyFrame"
local:layout_anchorGravity="bottom|right|end" />
</android.support.design.widget.CoordinatorLayout>
<!-- Left Side -->
<FrameLayout
android:id="#+id/navigationFrame"
android:layout_height="match_parent"
android:layout_width="240dp"
android:layout_gravity="left|start"
android:clickable="true" />
</android.support.v4.widget.DrawerLayout>
MainPage Layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.NavigationView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="#+id/navigation_view"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="start"
android:fitsSystemWindows="true"
android:theme="#style/ThemeToolbarNavigationView"
android:background="#color/colorPrimary"
local:itemTextColor="#color/light_gray"
local:itemIconTint="#color/light_gray"
local:headerLayout="#layout/navigation_header"
local:menu="#menu/navigation_drawer" />
Main ViewModel
public void ShowDefaultMenuItem()
{
NavigationService.Navigate<VacationRequestListViewModel>();
NavigationService.Navigate<MenuViewModel>();
}
Seems I'm losing small detail... Any help would be appreciated.
The problem was first of all in namespaces of attributes over the activities. They should be MvvmCross.Droid.Views.Fragments . And also instead of MvxFragmentAttribute we need to use MvxFragmentPresentationAttribute. Then it works.
I'm creating a layout which contains a maps (com.google.android.gms.maps.SupportMapFragment) & a mini layout to enter origin & destination(pickup_dropoff_LL LinearLayout).
XML
<RelativeLayout
android:id="#+id/main_RL"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/rideType_LL">
<include
android:id="#+id/pickup_dropoff_LL"
layout="#layout/layout_pickup_dropoff"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp" />
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity" />
</RelativeLayout>
Initially this had a corresponding Activity but I had to introduce a DrawerLayout so I had to convert it to a Fragment.
After doing that my pickup_dropoff_LL disappears.
It is shown on the screen for a micro second and then it disappears.
I suspect the issue is somewhere here but I'm not sure.
SupportMapFragment fm;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_main_activity, container, false);
fm = new SupportMapFragment() {
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
map = fm.getMap();
if (map != null) {
map.setMyLocationEnabled(true);
fm.getMapAsync(MainActivity2.this);
}
}
};
getChildFragmentManager().beginTransaction().add(R.id.main_RL, fm).commit();
return rootView;
}
1. I checked visibility for pickup_dropoff_LL. It's showing as 0, which means View.VISIBLE. But it is not visible.
2. As suggested by some links, I tried placing an empty view of same height & width over my map. Even that didn't work.
So how do I stop the view from disappearing?? Please help.
Try drawing your layout last. Put the Include after the Fragment
<RelativeLayout
android:id="#+id/main_RL"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/rideType_LL">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity" />
<include
android:id="#+id/pickup_dropoff_LL"
layout="#layout/layout_pickup_dropoff"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp" />
</RelativeLayout>
Have you tried moving your content inside of your drawer and not behind it?
<!-- Drawer Host inside the parent relative layout -->
<android.support.v4.widget.DrawerLayout
android:id="#+id/main_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Hold Fragment here -->
<FrameLayout
android:id="#+id/frag_main_host"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- Drawer -->
<RelativeLayout
android:id="#+id/drawer_pane"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start">
<!-- Menu list for drawer -->
<ListView
android:id="#+id/menu_list"
android:layout_height="match_parent"
android:layout_width="280dp"
android:dividerHeight="1sp"
android:gravity="start"
android:choiceMode="singleChoice" />
</RelativeLayout>
</android.support.v4.widget.DrawerLayout>
Putting anything below your view would make it not appear when opened although it is visible in property. In your class you can swap the fragment as desired by calling the fragment manager and seleting a fragment at whatever list index is selected. I suggest use an internal listener and just call a method to pick the view and swap it. Like below:
Listener (Internal class):
class MainDrawerItemClickListener implements AdapterView.OnItemClickListener{
#Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id ){
getView(position);
// close the drawers once selected
mDrawerLayout.closeDrawers();
}
}
That method will call this method in your main class:
// select the view
public void getView( int position ){
Fragment frag = null;
switch( position ){
case 0:
frag = new MyFragment();
break;
case 1:
frag = new MyOtherFragment();
break;
default:
break;
}
if( frag != null ){
swapView( frag );
}
}
// swaps the fragments
public void swapView( Fragment frag ){
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace( R.id.frag_main_host, frag ).commit();
}
Hope it helps, I know this is an old question, but I am sure someone will have the same question.
I need to add a map dynamically into the app to my MainActivity, otherwise I somehow suffer on memory leaks. Adding the map basically works, but I can't add markers. They just don't appear. That's how I add the map:
activity_main.xml which is used by the MainActivity
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Placeholder for all fragments -->
<RelativeLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</RelativeLayout>
<!-- Slider menu -->
<LinearLayout
android:id="#+id/list_container"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#fff"
android:orientation="vertical" >
<!-- more code -->
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
fragment_map.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center" >
<fragment
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="#+id/fragment_googlemap"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.androidmapsextensions.SupportMapFragment"
map:cameraTargetLat="48.21167860510698"
map:cameraTargetLng="16.365892895859423"
map:cameraZoom="11"
map:uiCompass="true"
map:uiRotateGestures="true"
map:uiScrollGestures="true"
map:uiTiltGestures="true"
map:uiZoomControls="true"
map:uiZoomGestures="true" />
</FrameLayout>
MapFragment.java
public class MapFragment extends com.androidmapsextensions.SupportMapFragment
{
private static final String TAG = MapFragment.class.getSimpleName();
private OnFragmentLoadedCompleteListener onFragmentLoadedCompleteListener;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle args)
{
super.onCreateView(inflater, container, args);
Logger.log(TAG, "onCreateView()", LogController.isLoggingEnabled(), Log.DEBUG);
return inflater.inflate(R.layout.fragment_map, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
Logger.log(TAG, "onActivityCreated()", LogController.isLoggingEnabled(), Log.DEBUG);
onFragmentLoadedCompleteListener.onFragmentComplete();
}
#Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
Logger.log(TAG, "onAttach()", LogController.isLoggingEnabled(), Log.DEBUG);
onFragmentLoadedCompleteListener = (OnFragmentLoadedCompleteListener)activity;
}
}
Important parts of MainActivity.java
#Override
public void onFragmentComplete()
{
googleMap = ((SupportMapFragment)getSupportFragmentManager().findFragmentByTag("mapFragment")).getExtendedMap();
}
private void initMapFragment()
{
if (googleMap != null)
{
googleMap.clear();
googleMap = null;
}
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MapFragment(), "mapFragment").commit();
}
OnFragmentLoadedCompleteListener.java
public interface OnFragmentLoadedCompleteListener
{
public void onFragmentComplete();
}
onFragmentComplete() is executed, googleMap is not null and shown. But I can't draw markers on it. They just don't appear.
But when I don't dynamically add the map and embed it into the activity_main.xml within the RelativeLayout like this
<RelativeLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="#+id/fragment_googlemap"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.androidmapsextensions.SupportMapFragment"
map:cameraTargetLat="48.21167860510698"
map:cameraTargetLng="16.365892895859423"
map:cameraZoom="11"
map:uiCompass="true"
map:uiRotateGestures="true"
map:uiScrollGestures="true"
map:uiTiltGestures="true"
map:uiZoomControls="true"
map:uiZoomGestures="true" />
</RelativeLayout>
and fetch the map like this without the listener, I can draw markers, that means they appear.
googleMap = ((SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.fragment_googlemap)).getExtendedMap();
That means drawing markers on the map only works when I directly embed the map into the xml of the MainActivity instead of added it dynamically as fragment. What's going on here. Where is the error?
As is often the case I found the solution on my own.
I have to keep a reference to my MapFragment I use to replace:
mapFragment = new MapFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, mapFragment).commit();
In onFragmentComplete() I have to invoke getChildFragmentManager() on this reference to obtain the "correct" GoogleMap.
googleMap = ((SupportMapFragment)mapFragment.getChildFragmentManager().findFragmentById(R.id.fragment_googlemap)).getExtendedMap();
This time it can be found by id as well (didn't work before), and drawing markers on this map works now.
I am following the Android Programming: The Big Nerd Ranch Guide and there is an example using ViewPager through the 2 files:
The file res/values/ids.xml defines an id in XML:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="viewPager" />
</resources>
And the Java source file CrimePagerActivity.java uses that id:
public class CrimePagerActivity extends FragmentActivity {
private ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.viewPager);
setContentView(mViewPager);
I have tried to change the example to have a ViewPager object being inflated from an XML layout file res/layout/crime_pager.xml (instead of just using an id):
<?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" >
<ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/view_pager" />
</LinearLayout>
And then I am trying to use that object in the CrimePagerActivity.java:
public class CrimePagerActivity extends FragmentActivity {
private ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.crime_pager);
mViewPager = (ViewPager)findViewById(R.id.view_pager);
Unfortunately, this does not work and fails with a RuntimeException and little info (here fullscreen):
What is the problem here please?
change:
<ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/view_pager" />
to
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>