In my application i have a sliding menu which has been developed by jfeinstein10.
It's working fine in my application ;)
I have a Fragment which is host of MapView. This fragment like my other fragments extended from Fragment class. Just in this Fragment, there is black cover/layer on top of menu contents when I open sliding menu. There is no black cover when I open menu in other fragments. Also, the thing that I found is height of box is exactly as same height as fragment.
Have you seen this problem before? any comments or suggestion would be appreciated.
=>
Update
Based on what Selei suggested I set background to transparent. However, regardless of what color I'm assigning (transparent or other colors) it's still visible and black :(
This is my code:
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
map:uiCompass="true"
android:background="#00000000"/>
The solution was adding map:zOrderOnTop="true" to XML.
For more info please refer to this link.
I tried all the methods here but none of them worked great. Using the GoogleOptions to move the zOrder to the top meant the basic zoom controls were hidden behind the map.
The last suggestion at this link: https://github.com/jfeinstein10/SlidingMenu/issues/168#issuecomment-17065660 (ckakei) fixed it for me.
The trick is to add an empty, transparent view to the layout:
<?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" >
<FrameLayout
android:id="#+id/view_map"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</FrameLayout>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent" />
I'm inflating this view then in a Fragment. I replace the view_map FrameLayout with the SuppportMapFragment.
This is the important part from that class:
private GoogleMap googleMap;
private SupportMapFragment mapFragment;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.view_map_layout, container,
false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getChildFragmentManager();
if (mapFragment == null) {
mapFragment = SupportMapFragment.newInstance();
}
if (savedInstanceState == null) {
mapFragment.setRetainInstance(true);
} else {
googleMap = mapFragment.getMap();
}
fm.beginTransaction().replace(R.id.view_map, mapFragment).commit();
}
set the MapView background transparent - android:background="#00000000"
I just made map copy view which copy the map when the sliding menu open or close
#SuppressWarnings("deprecation")
#SuppressLint("NewApi")
private void showMapCopy(boolean show) {
View map = findViewById(R.id.map);
View mapCopy = findViewById(R.id.map_copy);
if (show) {
map.setDrawingCacheEnabled(true);
Bitmap bitmap = map.getDrawingCache();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
mapCopy.setBackgroundDrawable(new BitmapDrawable(getResources(), bitmap));
else
mapCopy.setBackground(new BitmapDrawable(getResources(), bitmap));
mapCopy.setVisibility(View.VISIBLE);
} else {
map.setDrawingCacheEnabled(false);
mapCopy.setVisibility(View.GONE);
}
}
Sliding Menu Open Listener
mMenu.setOnClosedListener(new OnClosedListener() {
#Override
public void onClosed() {
showMapCopy(false);
}
});
OnOptionItemSelected
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.abs__home:
case android.R.id.home:
showMapCopy(true);
mMenu.toggle();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Related
I am working on a project that will have a 3D model viewer in one fragment. In order to do so, I decided to use sceneform. I have encountered a problem with SceneView, after trying to display it, in my tab fragment.
Everything is done according to examples and sceneform documentation, but sceneView display black screen, regardless of the colour I am assigning.
Here is scene loader
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
vw = inflater.inflate(R.layout.fragment_open_gl, container, false);
sceneView = vw.findViewById(R.id.scene_view);
return vw;
}
And fragment :
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".OpenGL">
<com.google.ar.sceneform.SceneView
android:id="#+id/scene_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/Crimson"/>
</FrameLayout>
I solved the issue by adding pausing and resuming sceneview, along with the fragment:
#Override
public void onPause() {
super.onPause();
sceneView.pause();
}
#Override
public void onResume() {
super.onResume();
try {
sceneView.resume();
} catch (CameraNotAvailableException e) {
e.printStackTrace();
}
}
So I've read several tutorials and many of the posts on SO but I still can't get this to work. I'm trying to use dynamically added fragments but when loading a fragment TextViews and ImageViews in the fragment keep overlapping instead of updating their values, like so:
and fragments overlap each other when replaced.
I got a main activity (extending AppCompatActivity) split into 2 layouts:
<LinearLayout 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/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background_white"
android:orientation="vertical"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/upperFrameLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/lowerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
...
The upper FrameLayout contains my fragments. The fragments are replaced in this method in the MainActivity-class:
void setMode() {
// Show "find opponent"- or "fight"-fragment
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if (!debugFight && (btCoordinator == null || !btCoordinator.isConnected())) {
fragmentTransaction.replace(R.id.upperFrameLayout, new FindOpponentFragment());
} else {
fragmentTransaction.replace(R.id.upperFrameLayout, new FightFragment());
}
fragmentTransaction.commitNow();
}
What am I missing?
EDIT: Added FightFragment onCreateView()-method:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
((TextView) inflater.inflate(R.layout.fragment_fight, container, false).findViewById(R.id.score_textView)).setText(getString(R.string.score, 0, 0));
((TextView) inflater.inflate(R.layout.fragment_fight, container, false).findViewById(R.id.opponent_textView)).setText(MainActivity.opponentName.toUpperCase());
final AnimatedVectorDrawableCompat animated = AnimatedVectorDrawableCompat.create(container.getContext(), R.drawable.loading_animated_vector);
animated.registerAnimationCallback(new Animatable2Compat.AnimationCallback() {
#Override
public void onAnimationEnd(Drawable drawable) {
animated.start();
}
});
((ImageView) inflater.inflate(R.layout.fragment_fight, container, false).findViewById(R.id.opponent_hand_imageview)).setImageDrawable(animated);
animated.start();
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_fight, container, false);
}
...and as I pasted this piece of code I just realised that those inflated views are all different objects. I replaced them with a single object which I modify and then let the method return and it works. I guess I have to read up on views and the inflate-method.
use fragmentTransaction. add() instead of replace()
Use this above the fragment commit
fragmentTransaction.addToBackStack(null);
I didn't understand how the inflate-method. I modified my fragments onCreateView-method as seen in the OP and now it works.
My application has 3 tabs and in one of them I want to display a map(HERE MAPS, not Google Maps). I was able to get the map to work perfectly in an Activity, but in Fragment Class when I try to cast the Fragment view to the MapFragment an error is thrown.
MapFragment mapFragment = (MapFragment)
getFragmentManager().findFragmentById(R.id.mapfragment);
Error:
Inconvetible types: cannot cast android.support.v4.app.support to com.here.android.mpa.mapping.MapFragment
Please correct me if Im wrong, but the reason for this to happen is because we canĀ“t use android.app.Fragment(used to display the map, as instructed in HERE MAPS DOC) in an android.support.v4.app.Fragment(used for the TabsLayout).
I found many questions related to this error using Google Maps. but just two(first,second)about the same error when using HERE MAPS, and none really helped to solve the problem.
In google Maps you can use SupportMapFragment(), but this mehod only works for Google Maps. Is there any solution for this using Here Maps? maybe a different approach to reach the same goal? or am I missing something when implementing this Here Maps in a TabLayout?
Any help will be appreciated!
My code:
MapFragment.java
public class Map extends Fragment {
public Map() {}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_map, container, false);
MapFragment mapFragment = (MapFragment)
getFragmentManager().findFragmentById(R.id.mapfragment);
mapFragment.init(new OnEngineInitListener() {
#Override
public void onEngineInitializationCompleted(
OnEngineInitListener.Error error) {
if (error == OnEngineInitListener.Error.NONE) {
com.here.android.mpa.mapping.Map map = mapFragment.getMap();
} else {
System.out.println("ERROR: Cannot initialize MapFragment");
}
}
};
return view;
}
fragment_map.xml
<FrameLayout 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"
tools:context="com.example.modulos.tabsMenu.Config">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="#+id/mapFragmentContainer"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
android:background="#aaa" >
<fragment
class="com.here.android.mpa.mapping.MapFragment"
android:id="#+id/mapfragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
android:background="#aaa" >
<!-- other things here -->
</LinearLayout>
</FrameLayout>
Since the HERE Maps SDK only works with API Level 15 and above, there's no support for compatibility fragments (that you mainly need when you target lower API levels).
In some cases you still want to deal with support fragment even if you have Android 4 or newer as target, in those cases you have to use the the MapView of the HERE SDK and embedded it in your layout on your own.
See this code example where also MapView is used: https://tcs.ext.here.com/sdk_examples/MapDownloader.zip
So, it will look like this:
Add in your layout the MapView:
<com.here.android.mpa.mapping.MapView
android:id="#+id/ext_mapview"
android:visibility="visible"
android:layout_width="match_parent"
android:layout_height="match_parent" />
And then in your code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mapView = (MapView) findViewById(R.id.ext_mapview);
MapEngine.getInstance().init(this, engineInitHandler);
}
private OnEngineInitListener engineInitHandler = new OnEngineInitListener() {
#Override
public void onEngineInitializationCompleted(Error error) {
if (error == Error.NONE) {
map = new Map();
mapView.setMap(map);
// more map initial settings
} else {
Log.e(TAG, "ERROR: Cannot initialize MapEngine " + error);
}
}
};
#Override
public void onResume() {
super.onResume();
MapEngine.getInstance().onResume();
if (mapView != null) {
mapView.onResume();
}
}
#Override
public void onPause() {
if (mapView != null) {
mapView.onPause();
}
MapEngine.getInstance().onPause();
super.onPause();
}
It's important that you handle the MapEngine and MapView Pause and Resume, otherwise you would get poor performance results.
Surely is a silliness ask this, but do you check if are you using MapFragment from the right package?
You must be using this class com.here.android.mpa.mapping.MapFragment, maybe by error you import this one com.google.android.gms.maps.MapFragment.
UPDATE: I thought it worked correctly. But after some test trouble still exists *sniff*
Then I made a simpler version to see what exactly happen and I get to know that the refreshing fragment which should have been detached still left there. Or exactly, the view of the old fragment left there, on top of the newer fragment. Since RecyclerView's background of my original app is not transparent, so It turned out what I said before.
END OF UPDATE
I have a MainActivity with layout like this:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="#+id/drawer_layout"
android:layout_width="match_parent" android:layout_height="match_parent">
<!-- As the main content view, the view below consumes the entire
space available using match_parent in both dimensions. -->
<FrameLayout android:id="#+id/container" android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
If you're not building against API 17 or higher, use
android:layout_gravity="left" instead. -->
<!-- The drawer is given a fixed width in dp and extends the full height of
the container. -->
<fragment android:id="#+id/navigation_drawer"
android:layout_width="#dimen/navigation_drawer_width" android:layout_height="match_parent"
android:layout_gravity="start" tools:layout="#layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>
The fragment ContentView I use to fill #id/container is configured as:
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/tweet_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/grey_300"/>
</android.support.v4.widget.SwipeRefreshLayout>
And here is onCreateView() of ContentView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View inflatedView = inflater.inflate(R.layout.fragment_content, container, false);
mRecyclerView = (RecyclerView) inflatedView.findViewById(R.id.tweet_list);
mRecyclerView.setHasFixedSize(false);
mLinearLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
mRecyclerView.setLayoutManager(mLinearLayoutManager);
mTweetList = new ArrayList<Tweet>;
mAdapter = new TweetAdapter(mTweetList);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mSwipeRefreshLayout = (SwipeRefreshLayout) inflatedView.findViewById(R.id.contentView);
mSwipeRefreshLayout.setOnRefreshListener(
...
);
return inflatedView;
}
Then in MainActivity I switch the content to display by switching different ContentView. All looks good except one thing: when I switch ContentView fragments DURING refreshing by navigation drawer, then content freezes. But actually all things work as usual except you cannot see it.
Well... After some struggling I eventually solved this problem by myself, in a tricky way...
I just need to add these in onPause() :
#Override
public void onPause() {
super.onPause();
...
if (mSwipeRefreshLayout!=null) {
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.destroyDrawingCache();
mSwipeRefreshLayout.clearAnimation();
}
}
This issue seems to still be occurring in appcompat 22.1.1. Wrapping the SwipeRefreshLayout inside a FrameLayout solved this for me
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/tweet_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/grey_300" />
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>
In addition to #zlm2012 answer, I noticed that this issue was reproduced under Support Library 21.0.0, but seems to be fixed right now at 21.0.3
The solution works, but I think it is better just put those lines into its own function, like:
public void terminateRefreshing() {
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.destroyDrawingCache();
mSwipeRefreshLayout.clearAnimation();
}
and call when switching the fragment.
Fragment prevFrag = fragmentManager.findFragmentById(drawerContainerId);
if(prevFrag instanceof SwipeRefreshFragment) {
((SwipeRefreshFragment)prevFrag).terminateRefreshing();
}
fragmentManager.beginTransaction().replace(drawerContainerId, fragment).commit();
It works! Just remove the transition from your fragment replacement, in my case I removed the following from my code:
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
Set clickable="true" in top parent layout... It may solve the problem.
For the time being, you can avoid the issue by:
public class FixedRefreshLayout extends SwipeRefreshLayout {
private static final String TAG = "RefreshTag";
private boolean selfCancelled = false;
public FixedRefreshLayout(Context context) {
super(context);
}
public FixedRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected Parcelable onSaveInstanceState()
{
if(isRefreshing()) {
clearAnimation();
setRefreshing(false);
selfCancelled = true;
Log.d(TAG, "For hide refreshing");
}
return super.onSaveInstanceState();
}
#Override
public void setRefreshing(boolean refreshing) {
super.setRefreshing(refreshing);
selfCancelled = false;
}
#Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if(hasWindowFocus && selfCancelled) {
setRefreshing(true);
Log.d(TAG, "Force show refreshing");
}
}
}
This has the added advantage of resuming the animation incase you decide to not switch the fragment (coming from some menu). It also ties in with the internal animation to make sure that the refreshing animation does not return if the network refresh has already completed.
Terminate SwipeRefresh whenever navigation menu item is clicked.
It worked.
private void selectItem(int position) {
mSwipeRefreshLayout.setRefreshing(false);
/*
Other part of the function
*/
}
I have an activity that hosts two fragments. One fragment provides some info to the user in various fields. The other fragment should show a Map.
For the fragment hosting the map I need to be able to add custom logic for displaying markers and several other things that I would like to reuse in other places in the app. What is the best way to create a map without defining the fragment in xml like:
<fragment
class="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Thanks,
Nathan
Edit:
I am now using nested fragments, not sure if that is the best way to handle this? My mapfragment is now:
<?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/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment" />
</LinearLayout>
and the Fragments code is:
public class ViewCurrentMapFragment extends Fragment implements View.OnClickListener {
public static final String TAG = "MAP_FRAGMENT";
private GoogleMap map;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_view_current_map, container, false);
return rootView;
}
private void getCurrentMarkers() {
// Getting reference to the SupportMapFragment of activity_main.xml
SupportMapFragment smf = ((SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.map));
map = smf.getMap();
}
#Override
public void onClick(View v) {
}
#Override
public void onResume() {
super.onResume();
getCurrentMarkers();
}
}
The problem I am having now is that smf.getMap() is returning null. Any ideas?
Edit2:
Got it to work by changing:
com.google.android.gms.maps.MapFragment
to
com.google.android.gms.maps.SupportMapFragment
Maybe:
<fragment
class="com.mycompany.MyCustomFragmentExtendingMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
or nest fragments like here: http://code.google.com/p/gmaps-api-issues/issues/detail?id=5064#c1