2013-04-09 63 views
1

我要讓谷歌地圖V2信息窗口是一種生活觀,讓我換SupportMapFragment自定義的RelativeLayout這樣的:dispatchTouchEvent觸發點擊事件不起作用?

R.layout.info_window:

<?xml version="1.0" encoding="utf-8"?> 
<com.Amazing.GoogleMapV2.MapWrapperLayout 
     xmlns:android="http://schemas.android.com/apk/res/android" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:id="@+id/map_relative_layout"> 
    <fragment 
      android:id="@+id/map" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      class="com.google.android.gms.maps.SupportMapFragment" /> 
</com.Amazing.GoogleMapV2.MapWrapperLayout> 

我重寫dispatchTouchEvent,偏移motionEvent位置信息窗口視圖座標,然後向dispatchTouchEvent信息窗口: MapWrapperLayout:

public class MapWrapperLayout extends RelativeLayout { 
    /** 
    * Reference to a GoogleMap object 
    */ 
    private GoogleMap map; 

    /** 
    * Vertical offset in pixels between the bottom edge of our InfoWindow 
    * and the marker position (by default it's bottom edge too). 
    * It's a good idea to use custom markers and also the InfoWindow frame, 
    * because we probably can't rely on the sizes of the default marker and frame. 
    */ 
    private int bottomOffsetPixels; 

    /** 
    * A currently selected marker 
    */ 
    private Marker marker; 

    /** 
    * Our custom view which is returned from either the InfoWindowAdapter.getInfoContents 
    * or InfoWindowAdapter.getInfoWindow 
    */ 
    private View infoWindow; 

    public MapWrapperLayout(Context context) { 
     super(context); 
    } 

    public MapWrapperLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public MapWrapperLayout(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    /** 
    * Must be called before we can route the touch events 
    */ 
    public void init(GoogleMap map, int bottomOffsetPixels) { 
     this.map = map; 
     this.bottomOffsetPixels = bottomOffsetPixels; 
    } 

    /** 
    * Best to be called from either the InfoWindowAdapter.getInfoContents 
    * or InfoWindowAdapter.getInfoWindow. 
    */ 
    public void setMarkerWithInfoWindow(Marker marker, View infoWindow) { 
     this.marker = marker; 
     this.infoWindow = infoWindow; 
    } 

    @Override 
    public boolean dispatchTouchEvent(MotionEvent ev) { 
     // Make sure that the infoWindow is shown and we have all the needed references 
     if (marker != null && marker.isInfoWindowShown() && map != null && infoWindow != null) { 
      // Get a marker position on the screen 
      Point point = map.getProjection().toScreenLocation(marker.getPosition()); 

      // Make a copy of the MotionEvent and adjust it's location 
      // so it is relative to the infoWindow left top corner 
      MotionEvent copyEv = MotionEvent.obtain(ev); 
      copyEv.offsetLocation(
        -point.x + (infoWindow.getWidth()/2), 
        -point.y + infoWindow.getHeight() + bottomOffsetPixels); 
      Log.e("~~~~~~~~~~dispatchTouchEvent copyEv", copyEv.toString()); 

      //Dispatch the adjusted MotionEvent to the infoWindow 
      if (infoWindow.dispatchTouchEvent(copyEv)) { 
       Log.e("infoWindow.dispatchTouchEvent(copyEv)", "True"); 
       Log.e("~~~~~~~~~~dispatchTouchEvent point", point.toString()); 
       Log.e("~~~~~~~~~~dispatchTouchEvent ev", ev.toString()); 
       Log.e("~~~~~~~~~~dispatchTouchEvent copyEv", copyEv.toString()); 
       return true; 
      } 
     } 
     // If the infoWindow consumed the touch event, then just return true. 
     // Otherwise pass this event to the super class and return it's result 
     return super.dispatchTouchEvent(ev); 
    } 
} 

R.layout.info_window:

<?xml version="1.0" encoding="utf-8"?> 

<LinearLayout 
     xmlns:android="http://schemas.android.com/apk/res/android" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:gravity="center_vertical"> 

    <LinearLayout 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:orientation="vertical" 
      android:layout_marginRight="10dp"> 

     <TextView 
       android:id="@+id/title" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:textSize="18sp" 
       android:text="Title"/> 

     <TextView 
       android:id="@+id/snippet" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:text="snippet"/> 

    </LinearLayout> 

    <Button 
      android:id="@+id/button" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="Button" android:clickable="true" android:enabled="true" android:focusable="true" 
      android:focusableInTouchMode="true"/> 

</LinearLayout> 

而且MainActivity膨脹R.layout.info_window和setOnClickListener到infoButton這是對info_window: MainActivity:

public class MainActivity extends SherlockFragmentActivity { 
     private ViewGroup infoWindow; 
     private TextView infoTitle; 
     private TextView infoSnippet; 
     private Button infoButton; 
    // private OnInfoWindowElemTouchListener infoButtonListener; 

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

      final SupportMapFragment mapFragment = 
        (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map); 
      final MapWrapperLayout mapWrapperLayout = 
        (MapWrapperLayout)findViewById(R.id.map_relative_layout); 
      final GoogleMap map = mapFragment.getMap(); 

      // MapWrapperLayout initialization 
      // 39 - default marker height 
      // 20 - offset between the default InfoWindow bottom edge and it's content bottom edge 
      mapWrapperLayout.init(map, getPixelsFromDp(this, 39 + 20)); 

      // We want to reuse the info window for all the markers, 
      // so let's create only one class member instance 
      this.infoWindow = (ViewGroup)getLayoutInflater().inflate(R.layout.info_window, null); 
      this.infoTitle = (TextView)infoWindow.findViewById(R.id.title); 
      this.infoSnippet = (TextView)infoWindow.findViewById(R.id.snippet); 
      this.infoButton = (Button)infoWindow.findViewById(R.id.button); 
      // Setting custom OnTouchListener which deals with the pressed state 
      // so it shows up 
    //  this.infoButtonListener = new OnInfoWindowElemTouchListener(infoButton, 
    //    R.drawable.btn_normal, R.drawable.btn_pressed) 
    //  { 
    //   @Override 
    //   protected void onClickConfirmed(View v, Marker marker) { 
    //    // Here we can perform some action triggered after clicking the button 
    //    Toast.makeText(MainActivity.this, marker.getTitle() + "'s button clicked!", Toast.LENGTH_SHORT).show(); 
    //   } 
    //  }; 
      this.infoButton.setOnClickListener(new View.OnClickListener() { 
       @Override 
       public void onClick(View view) { 
        Toast.makeText(MainActivity.this, "~~~~~ Button clicked!", Toast.LENGTH_SHORT).show(); 
       } 
      }); 

      map.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() { 
       @Override 
       public View getInfoWindow(Marker marker) { 
        return null; 
       } 

       @Override 
       public View getInfoContents(Marker marker) { 
        // Setting up the infoWindow with current's marker info 
        infoTitle.setText(marker.getTitle()); 
        infoSnippet.setText(marker.getSnippet()); 
    //    infoButtonListener.setMarker(marker); 

        // We must call this to set the current marker and infoWindow references 
        // to the MapWrapperLayout 
        mapWrapperLayout.setMarkerWithInfoWindow(marker, infoWindow); 
        return infoWindow; 
       } 
      }); 

      // Let's add a couple of markers 
      map.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(50.08, 14.43))); 
      map.addMarker(new MarkerOptions() 
        .title("Prague") 


    .snippet("Czech Republic") 
       .position(new LatLng(50.08, 14.43))); 

     map.addMarker(new MarkerOptions() 
       .title("Paris") 
       .snippet("France") 
       .position(new LatLng(48.86,2.33))); 

     Marker m = map.addMarker(new MarkerOptions() 
       .title("London") 
       .snippet("United Kingdom") 
       .position(new LatLng(51.51,-0.1))); 
     m.showInfoWindow(); 
    } 

    public static int getPixelsFromDp(Context context, float dp) { 
     final float scale = context.getResources().getDisplayMetrics().density; 
     return (int)(dp * scale + 0.5f); 
    } 
} 

這些代碼行爲奇怪,按鈕的onClick將在活動onResume()不立即致電時致電, 但onTouch事件立即致電。 爲什麼?

回答

1

我認爲這可能與這個問題有關。

Runnable is posted successfully but not run

的問題是,在View.onTouchEvent(MotionEvent事件)當ACTION_UP事件發生,而不是僅僅調用performClick()調用的Android用PerformClick可運行後()。此runnable不會運行,因爲您的視圖未附加到窗口。

要解決該問題,只需將視圖添加到MapWrapperLayout。你甚至可以把它放在屏幕上,這樣它就不會影響地圖的外觀。

public void setMarkerWithInfoWindow (Marker marker, View infoWindow) 
{ 
    this.marker = marker; 

    if (this.infoWindow != null) 
    { 
     this.removeView (this.infoWindow); 
    } 
    this.infoWindow = infoWindow; 

    // Force the view to render WAY off screen, so we don't actually see it. 
    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams (
      LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 
    params.leftMargin = 100000; 

    this.addView (infoWindow, params); 
}