Making a Snackbar Without a View?
I want to show a snackbar as soon as the user opens the Google Maps activity, but the thing is that there's no views in the activity to use as the first parameter of the activity (in the findViewById()
of Snackbar.make()
). What do I put there?
Here's the java class code:
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setBuildingsEnabled(true);
mMap.getUiSettings().setZoomControlsEnabled(true);
float cameraZoom = 17;
LatLng location = new LatLng(43.404032, -80.478184);
mMap.addMarker(new MarkerOptions().position(location).title("49 McIntyre Place #18, Kitchener, ON N2R 1G3"));
CameraUpdateFactory.newLatLngZoom(location, cameraZoom);
Snackbar.make(findViewById(/*WHAT DO I PUT HERE?*/), "Click the pin for more options", Snackbar.LENGTH_LONG).show();
}
}
Also, here is the activity xml code:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
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="ca.davesautoservice.davesautoservice.MapsActivity" />
And lastly, here's the stacktrace error:
08-03 11:42:21.333 3901-3901/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: ca.davesautoservice.davesautoservice, PID: 3901
java.lang.NullPointerException
at android.support.design.widget.Snackbar.<init>(Snackbar.java:183)
at android.support.design.widget.Snackbar.make(Snackbar.java:215)
at ca.davesautoservice.davesautoservice.MapsActivity.onMapReady(MapsActivity.java:48)
at com.google.android.gms.maps.SupportMapFragment$zza$1.zza(Unknown Source)
at com.google.android.gms.maps.internal.zzo$zza.onTransact(Unknown Source)
at android.os.Binder.transact(Binder.java:361)
at xz.a(:com.google.android.gms.DynamiteModulesB:82)
at maps.ad.u$5.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5333)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:828)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:644)
at dalvik.system.NativeStart.main(Native Method)
Thanks for the help! :)
I see some options... Not sure which one can fix your issue.
Simpliest
SupportMapFragment
extends class android.support.v4.app.Fragment
. This way, it has a method getView()
Snackbar.make(mapFragment.getView(), "Click the pin for more options", Snackbar.LENGTH_LONG).show();
Find Root View
From this answer, there's a way to get the root view via:
getWindow().getDecorView().getRootView()
So, maybe, you can do:
Snackbar.make(getWindow().getDecorView().getRootView(), "Click the pin for more options", Snackbar.LENGTH_LONG).show();
NOTE: This approach has the side effect mentioned in the comments below:
The message will be shown behind the bottom navigation bar if the following method will be used to get view getWindow().getDecorView().getRootView()
Add a dummy LinearLayout to get the View
Honestly, I'm not sure if this solution is possible. I'm not sure if you can add a LinearLayout above the Maps fragment... I think it is OK but since I never work with Maps API before, I'm not sure.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dummy_layout_for_snackbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
xmlns:map="http://schemas.android.com/apk/res-auto"
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="ca.davesautoservice.davesautoservice.MapsActivity" />
</LinearLayout>
and then:
Snackbar.make(findViewById(R.id.dummy_layout_for_snackbar), "Click the pin for more options", Snackbar.LENGTH_LONG).show();
Try this in any activity:
snackbar(findViewById(android.R.id.content),"your text")
As Shahab Rauf points out, getting the view via getDecorView() may put the snackbar behind the navigation bar in the bottom. I use the following code: (Use and extend to your delight)
public class BaseActivity extends AppCompatActivity {
private View getRootView() {
final ViewGroup contentViewGroup = (ViewGroup) findViewById(android.R.id.content);
View rootView = null;
if(contentViewGroup != null)
rootView = contentViewGroup.getChildAt(0);
if(rootView == null)
rootView = getWindow().getDecorView().getRootView();
return rootView;
}
protected void showSnackBarWithOK(@StringRes int res) {
final View rootView = getRootView();
if(rootView != null) {
final Snackbar snackbar = Snackbar.make(getRootView(), res, Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.ok, new View.OnClickListener() {
@Override
public void onClick(View v) {
snackbar.dismiss();
}
});
snackbar.show();
}
}
protected void showSnackBar(@StringRes int res) {
final View rootView = getRootView();
if(rootView != null)
Snackbar.make(rootView, res, Snackbar.LENGTH_LONG).show();
}
}
OK, So all above solutions are either too complex or irrelevant.
Simplest solution is to use this function ANYWHERE
fun showSnackBar(message: String?, activity: Activity?) {
if (null != activity && null != message) {
Snackbar.make(
activity.findViewById(android.R.id.content),
message, Snackbar.LENGTH_SHORT
).show()
}
}
Wanna call this function in Activity?
showSnackBar("Test Message in snackbar", this)
Wanna call this function in Fragment?
showSnackBar("Test Message in snackbar", requireActivity())
Happy Coding!
The simplest way of doing this is to get the advantage of Extention Function in Kotlin.
Step 1: Create a kotlin file i.e Extensions.kt
and paste below code
For Activity:
fun Activity.showSnackBar(msg:String){
Snackbar.make(this.findViewById(android.R.id.content), msg, Snackbar.LENGTH_SHORT)
.setAction("Ok"){
}
.show()
}
For Fragment:
fun Fragment.showSnackBar(msg:String){
Snackbar.make(this.requireActivity().findViewById(android.R.id.content), msg, Snackbar.LENGTH_SHORT)
.setAction("Ok"){
}
.show()
}
Step 2: Call it like below:
showSnackBar("PASS HERE YOUR CUSTOM MESSAGE")