誰かがそれを必要とする場合、これは私がした方法です:
- ユーザー アクションをインターセプトし、マップの拡大/縮小を制御する LinearLayout を定義します。
- 相対レイアウト内に mapFragment v2.0 を配置しました。
- マップを拡大縮小するときのスクロール ビューのサイズを定義します。
このフラグメントのレイアウト:
<?xml version="1.0" encoding="utf-8"?>
<com.snapcar.rider.utils.LinearTouchEventLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:pj="http://schemas.android.com/apk/res/com.snapcar.rider"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_red"
android:orientation="vertical" >
<RelativeLayout
android:id="@+id/map_fragment_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</RelativeLayout>
<ScrollView
android:id="@+id/scrollView1"
style="@style/sc_scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="5" >
Layout content
</ScrollView>
</com.snapcar.rider.utils.LinearTouchEventLayout>
LinearLayout の拡張:
package com.snapcar.rider.utils;
import android.content.Context;
import android.support.v4.app.NotificationCompat.Action;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
public class LinearTouchEventLayout extends LinearLayout {
private static final String TAG = "LinearTouchEventLayout";
RelativeLayout mapContainer;
ScrollView mScroll;
public LinearTouchEventLayout(Context context) {
super(context);
setLinearTouchEventLayoutListener((LinearTouchEventLayoutListener) context);
for(int i=0; i<getChildCount(); ++i) {
View nextChild = getChildAt(i);
if (nextChild instanceof RelativeLayout) mapContainer = (RelativeLayout) nextChild;
if (nextChild instanceof ScrollView) mScroll = (ScrollView) nextChild;
}
Dbg.d(TAG, "first constructor ended");
// TODO Auto-generated constructor stub
}
public LinearTouchEventLayout(Context context, AttributeSet aset) {
super(context, aset);
setLinearTouchEventLayoutListener((LinearTouchEventLayoutListener) context);
for(int i=0; i<getChildCount(); ++i) {
View nextChild = getChildAt(i);
if (nextChild instanceof RelativeLayout) mapContainer = (RelativeLayout) nextChild;
if (nextChild instanceof ScrollView) mScroll = (ScrollView) nextChild;
}
if (mapContainer == null) Dbg.d(TAG, "mapContainer is null");
if (mScroll == null) Dbg.d(TAG, "mScroll is null");
Dbg.d(TAG, "second constructor ended");
}
private boolean isMapExpand = false;
public boolean isMapExpand() {
return isMapExpand;
}
public void setMapExpand(boolean isMapExpand) {
this.isMapExpand = isMapExpand;
}
public interface LinearTouchEventLayoutListener {
void onTouch();
void onShrinkMap();
}
private LinearTouchEventLayoutListener mListener;
public void setLinearTouchEventLayoutListener(LinearTouchEventLayoutListener listener) {
mListener = listener;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Dbg.d(TAG,"Event - onInterceptTouchEvent");
for(int i=0; i<getChildCount(); ++i) {
View nextChild = getChildAt(i);
if (nextChild instanceof RelativeLayout) mapContainer = (RelativeLayout) nextChild;
if (nextChild instanceof ScrollView) mScroll = (ScrollView) nextChild;
}
if (mapContainer != null && isPointInsideView(ev.getX(), ev.getY(), mapContainer)) Dbg.e(TAG, "inside mapContainer");
if (mScroll != null && isPointInsideView(ev.getX(), ev.getY(), mScroll)) Dbg.e(TAG, "inside mScroll");
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// Dbg.d(TAG,"ACTION_DOWN");
if (mapContainer != null && isPointInsideView(ev.getX(), ev.getY(), mapContainer)) {
// Dbg.e(TAG, "inside mapContainer");
if (!isMapExpand && mListener != null) {
mListener.onTouch();
isMapExpand = !isMapExpand;
return true;
}
if (isMapExpand) {
return false;
}
}
if (mScroll != null && isPointInsideView(ev.getX(), ev.getY(), mScroll) && isMapExpand && mListener != null) {
mListener.onShrinkMap();
isMapExpand = !isMapExpand;
return true;
}
break;
case MotionEvent.ACTION_MOVE:
// Dbg.d(TAG,"ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
// Dbg.d(TAG,"ACTION_UP");
break;
case MotionEvent.ACTION_SCROLL:
// Dbg.d(TAG,"ACTION_SCROLL");
break;
}
return false;
// if (isMapExpand) { // just to be sure sure
// onTouchEvent(ev);
// }
// return super.onInterceptTouchEvent(ev);
//return false; //event get propagated
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// Dbg.d(TAG, "Event - dispatchTouchEvent");
// if (isMapExpand) { //in this case we want to stop dispatching & handle the even ourself.
// System.out.println("dispatchTouchEvent - Map is E x p a n d e d");
// onInterceptTouchEvent(ev);
// return true; //the even will be consumed
// } else { // Usual process
// System.out.println("dispatchTouchEvent - Map is shrinked");
// return super.dispatchTouchEvent(ev);
// }
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// Dbg.d(TAG, "Event - onTouchEvent");
// if (isMapExpand) {
// System.out.println("onTouchEvent - Map is E x p a n d e d - onTouch");
// //BookingFormFragment.this.shrinkMap();
// return true;
// } else {
// System.out.println("onTouchEvent - usual process");
// return super.onTouchEvent(event);
// }
//
return super.onTouchEvent(event);
}
/**
* Determines if given points are inside view
* @param x - x coordinate of point
* @param y - y coordinate of point
* @param view - view object to compare
* @return true if the points are within view bounds, false otherwise
*/
boolean isPointInsideView (float x, float y, View view) {
int location[] = new int[2];
view.getLocationOnScreen(location);
int viewX = view.getLeft();
int viewY = view.getTop();
// Dbg.d(TAG,"viewX = "+viewX);
// Dbg.d(TAG,"viewY = "+viewY);
// Dbg.d(TAG,"view.getWidth() = "+view.getWidth());
// Dbg.d(TAG,"view.getHeight() = "+view.getHeight());
// Dbg.d(TAG,"eventX = "+x);
// Dbg.d(TAG,"eventY = "+y);
//point is inside view bounds
if(( x > viewX && x < (viewX + view.getWidth())) &&
( y > viewY && y < (viewY + view.getHeight()))){
// Dbg.d(TAG, "Point is INSIDE view");
return true;
} else {
// Dbg.d(TAG, "Point is OUT SIDE view");
return false;
}
}
}
そして少なくともフラグメントクラスの便利なメソッド:
OnCreate コールバック:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Dbg.v(TAG, "- onCreateView bookingFormFragment");
root = inflater.inflate(R.layout.fragment_booking_form, null);
root.setOnClickListener(this);
mScroll = (ScrollView) root.findViewById(R.id.scrollView1);
/*
* Map Fragment
*/
FragmentManager fm = getChildFragmentManager();
mapFragment = new CustomMapFragment();
fm.beginTransaction().replace(R.id.map_fragment_container, mapFragment).commit();
things I need to set up the menu item and the scroll content
}
縮小/拡大方法:
private void shrinkMap() {
Dbg.d(TAG, "shrinkMap");
DropDownAnim anim = new DropDownAnim(mScroll, false);
anim.setDuration(300);
anim.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
Dbg.d(TAG, "DropDownAnim - shrink start");
isShrinking = true;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
Dbg.d(TAG, "DropDownAnim shrink end");
isShrinking = false;
isMapShrinked = true;
adjustMapPosAndZoom();
}
});
getView().startAnimation(anim);
}
そしてもちろんアニメーション定義:
private class DropDownAnim extends Animation {
boolean down;
float maxRatio = 5;
float minRatio = 0.2f;
public DropDownAnim(View view, boolean down) {
this.down = down;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float currentRatio;
if (down) {
currentRatio = maxRatio - (float) ((maxRatio - minRatio) * interpolatedTime);
} else {
currentRatio = minRatio + (float) ((maxRatio - minRatio) * interpolatedTime);
}
LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
0, (float) currentRatio);
Dbg.d(TAG, "--- "+ currentRatio);
mScroll.setLayoutParams(param2);
root.requestLayout();
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
@Override
public boolean willChangeBounds() {
return true;
}
}
ご不明な点がございましたら、お気軽にお問い合わせください。