Search code examples
androidpopupmapspopupwindow

Close PopupWindow upon tapping outside or back button


I want to close a PopupWindow by either tapping outside the window or pressing a back button. Right now you can tap anywhere on the screen and the window closes, and I can't figure out why. I'd also like to add a shadow to the PopupWindow. Thanks!

MainActivity.Java:

public class MainActivity extends FragmentActivity implements OnMapReadyCallback, GoogleMap.OnMarkerClickListener{

LinearLayout mainLayout;

private GoogleMap mMap;
PlaceAutocompleteFragment placeAutoComplete;
private static final String TAG = "Main Activity";
List<Marker> list = new ArrayList<>();

Marker NY_MANHATTAN;
Marker NY_BROOKLYN;
Marker NY_BRONX;
Marker NY_QUEENS;
Marker NY_STATENISLAND;

private PopupWindow popupWindow;
private LayoutInflater layoutInflater;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //TODO:initialize startup stuff here:

    /*
    * layoutTest is the testing inflater for all popup windows.
    * here is where new popup windows will be added to the list.
    * */

    mainLayout = (LinearLayout) findViewById(R.id.mainLayout);



    placeAutoComplete = (PlaceAutocompleteFragment) getFragmentManager().findFragmentById(R.id.place_autocomplete);
    placeAutoComplete.setOnPlaceSelectedListener(new PlaceSelectionListener() {
        @Override
        public void onPlaceSelected(Place place) {

            Log.i(TAG, "Place Selected: " + place.getName());
            LatLng latLng = place.getLatLng();

            //move map camera
            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 11));
        }

        @Override
        public void onError(Status status) {
            Log.d("Maps", "An error occurred: " + status);
        }
    });

    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
}

@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

    try {
        // Customise the styling of the base map using a JSON object defined
        // in a raw resource file.
        boolean success = googleMap.setMapStyle(
                MapStyleOptions.loadRawResourceStyle(
                        this, R.raw.style_json));

        if (!success) {
            Log.e(TAG, "Style parsing failed.");
        }
    } catch (Resources.NotFoundException e) {
        Log.e(TAG, "Can't find style. Error: ", e);
    }

    //TODO: DEFINE MARKER LOCATIONS HERE:

    LatLng manhattanLoc = new LatLng(40.754932, -73.984016);
    LatLng brooklynLoc = new LatLng(40.650002, -73.949997);
    LatLng bronxLoc = new LatLng(40.837048, -73.865433);
    LatLng queensLoc = new LatLng(40.742054, -73.769417);
    LatLng statenIslandLoc = new LatLng(40.579021, -74.151535);

    //TODO: INIT MARKERS HERE:


     NY_MANHATTAN = googleMap.addMarker(new MarkerOptions().position(manhattanLoc).title("Manhattan").snippet("test"));
    list.add(NY_MANHATTAN);

     NY_BROOKLYN = googleMap.addMarker(new MarkerOptions().position(brooklynLoc).title("Brooklyn").snippet("test"));
    list.add(NY_BROOKLYN);

     NY_BRONX = googleMap.addMarker(new MarkerOptions().position(bronxLoc).title("Bronx").snippet("test"));
    list.add(NY_BRONX);

     NY_QUEENS = googleMap.addMarker(new MarkerOptions().position(queensLoc).title("Queens").snippet("test"));
    list.add(NY_QUEENS);

     NY_STATENISLAND = googleMap.addMarker(new MarkerOptions().position(statenIslandLoc).title("Staten Island").snippet("test"));
    list.add(NY_STATENISLAND);

    googleMap.setOnCameraChangeListener(new
                                                GoogleMap.OnCameraChangeListener() {
                                                    @Override
                                                    public void onCameraChange(CameraPosition cameraPosition) {
                                                        for (Marker m : list) {
                                                            m.setVisible(cameraPosition.zoom > 10); // <-- define zoom level for markers here
                                                            /**
                                                             * Zoom level guidelines:
                                                             * 12 = zoomed in about 90%
                                                             * 1 = zommed in less than 5%
                                                             * Higher = higher zoom, Lower = lower zoom.
                                                             * Confusing. I know.
                                                             */
                                                        }
                                                    }
                                                });

    mMap.setOnMarkerClickListener(this);

}

//TODO: handle marker clicks below:
/*
* current placeholder code states that all markers
* will open the popup_test layout.
* */

public boolean onMarkerClick(Marker arg0) {

    PopupInit();

    return false;

}

public void PopupInit()
{

    layoutInflater = (LayoutInflater) getApplicationContext().getSystemService(LAYOUT_INFLATER_SERVICE);
    ViewGroup container = (ViewGroup) layoutInflater.inflate(R.layout.popup_test,null);

    /*
    *
    * set x/y locations here:
    *
    * */

    DisplayMetrics dm = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(dm);

    int popWidth = dm.widthPixels;
    int popHeight = dm.heightPixels;

    popupWindow = new PopupWindow(container,(int) (popWidth*.8),(int) (popHeight*.6),true);
    popupWindow.showAtLocation(mainLayout, Gravity.CENTER,0,0);

    container.setOnTouchListener(new View.OnTouchListener()
    {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent)
        {
            popupWindow.dismiss();
            return true;
        }
    });


}



}

Popup_Test.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="#fff55250"
    android:layout_width="match_parent" 
android:layout_height="match_parent">
</RelativeLayout>

Sorry about the noob question. I've been at this for a while and I just can't seem to figure out no matter how much I try... my biggest two concerns are getting the shadow behind the popupwindow and also closing it upon the press of the back button or tapping outside the popup window. thanks very much in advance. thanks.


Solution

  • You will need to set Background Drawable using and on Outside touch true

    popWindow.setFocusable(true);
    popupWindow.setBackgroundDrawable(new ColorDrawable())
    popupWindow.setOutsideTouchable(true);
    

    method by passing any drawable. Otherwise the whole screen is your background and tapping outside will not work backPressed will work automatically using this way!

    To add a shadow to you PopupWindow the easier way is to put CardView as the root of your View in xml and change elevation attribute. To use CardView you may have to add a dependency it in your gradle file as well

      <android.support.v7.widget.CardView
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_view"
        android:layout_gravity="center"
        android:layout_width="200dp"
        android:layout_height="200dp"
        card_view:cardElevation="4dp"
        card_view:cardCornerRadius="4dp">
    
        <!--YOUR RELATIVE LAYOUT SHOULD BE HERE!-->
    
    </android.support.v7.widget.CardView>
    

    You also have to add dependency in your app gradle files like:

    dependencies {
    ...
        compile 'com.android.support:cardview-v7:21.0.+'
    }
    

    More details in CardView and elevation here.

    THIS IS HOW IT LOOKS IN MY CODE

        LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    
        // inflate the custom popup layout
        final View inflatedView = layoutInflater.inflate(R.layout.pop_up_test, null,false);
        // get device size
        Display display = getWindowManager().getDefaultDisplay();
        final Point size = new Point();
        display.getSize(size);
        //mDeviceHeight = size.y; //Not in use just comment it off for now
    
        // set height depends on the device size
        popupWindow = new PopupWindow(inflatedView, size.x - 50,(WindowManager.LayoutParams.WRAP_CONTENT), true );
        // set a background drawable with rounders corners
        // make it focusable to show the keyboard to enter in `EditText`
        popupWindow.setFocusable(true);
        popupWindow.setBackgroundDrawable(new ColorDrawable());//This has no meaning than dismissal of the Pop Up Noni!!
        // make it outside touchable to dismiss the popup window
        popupWindow.setOutsideTouchable(true);
    
        // show the popup at bottom of the screen and set some margin at bottom ie,
        popupWindow.showAtLocation(v, Gravity.BOTTOM, 0,100);