创建叠加ImageView动画Google地图

时间:2016-10-02 19:51:07

标签: android google-maps imageview android-animation google-maps-android-api-2

我正在尝试让我的叠加图像执行以下操作:

  • onMap / onDrag的地图,在地图中间显示一个恒定的图像 这是一个针
  • onTouchUp,将标记图像更改为加载标记和数据 加载完整更改将图像加载到带图文的新图像。

这是一个非常类似于我的问题的解决方案:

animatedMarker

到目前为止我做了什么?

  • 在我的谷歌地图中间放置了一个imageview,然后得到了 使用mMap.getCameraPosition().target放弃该imageView 它使用给出大约中间位置坐标 setOnCameraChanged,我知道已经弃用了,有更好的 溶液?
  • 其余的部分我无法弄清楚,虽然我已经阅读了几个SO问题声称他们已经实现了将framelayout包装在谷歌地图的片段上,并在其上应用onTouch,但无法找到真正的答案一个也是。

我的xml片段所有这些都发生了这样:

<RelativeLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".fragments.MovableMapFragment">

    <fragment
        android:id="@+id/map_frag_fmm"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/tablayout_global_tabs"
        android:layout_alignParentTop="true" />
<! -- long xml ahead -->

有人知道如何实现这种行为吗?

3 个答案:

答案 0 :(得分:7)

Android Custom Pin

最好的解决方案是使用RxJava / RxAndroid并使用它执行后台任务,但我无法在不查看代码的情况下使用rx发布解决方案,而且@ user27799也是@的示例Manas Chaudhari对逻辑提供了很好的解释(下面)。

//bunch of imports
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;

public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback
{

  private GoogleMap mGoogleMap;
  private FrameLayout frameLayout, circleFrameLayout;
  private ProgressBar progress;
  private TextView textView;
  private int circleRadius;
  private boolean isMoving = false;
  private SupportMapFragment mapFragment;

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

  private void initViews() {

    frameLayout = (FrameLayout) findViewById(R.id.map_container);

    circleFrameLayout = (FrameLayout) frameLayout.findViewById(R.id.pin_view_circle);
    textView = (TextView) circleFrameLayout.findViewById(R.id.textView);
    progress = (ProgressBar) circleFrameLayout.findViewById(R.id.profile_loader);

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

}

  private void moveMapCamera() {
    if (mGoogleMap == null) {
        return;
    }

    CameraUpdate center = CameraUpdateFactory
            .newLatLng(new LatLng(40.76793169992044, -73.98180484771729));
    CameraUpdate zoom = CameraUpdateFactory.zoomTo(15);

    mGoogleMap.moveCamera(center);
    mGoogleMap.animateCamera(zoom);
}

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

    mGoogleMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {

        /* User starts moving map - change your pin's image here 
        */
        @Override
        public void onCameraMoveStarted(int i) {
            isMoving = true;
            textView.setVisibility(View.GONE);
            progress.setVisibility(View.GONE);
            Drawable mDrawable;
            if (Build.VERSION.SDK_INT >= 21)
                mDrawable = getApplicationContext().getResources().getDrawable(R.drawable.circle_background_moving, null);
            else
                mDrawable = getApplicationContext().getResources().getDrawable(R.drawable.circle_background_moving);

            circleFrameLayout.setBackground(mDrawable);
            resizeLayout(false);
        }
    });

    /*User stoped moving map -> retrieve location and do your background task */
    mGoogleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
        @Override
        public void onCameraIdle() {

            isMoving = false;
            textView.setVisibility(View.INVISIBLE);
            progress.setVisibility(View.VISIBLE);
            resizeLayout(true);

            /* this is just an example that simulates data loading
               you shoud substitute it with your logic
            */
            new Handler().postDelayed(new Runnable() {
                public void run() {

                    Drawable mDrawable;
                    if (Build.VERSION.SDK_INT >= 21)
                        mDrawable = getApplicationContext().getResources().getDrawable(R.drawable.circle_background, null);
                    else
                        mDrawable = getApplicationContext().getResources().getDrawable(R.drawable.circle_background);

                    if (!isMoving) {
                        circleFrameLayout.setBackground(mDrawable);
                        textView.setVisibility(View.VISIBLE);
                        progress.setVisibility(View.GONE);
                    }
                }
            }, 1500);
        }
    });

    MapsInitializer.initialize(this);
    moveMapCamera();
  }

  //resing circle pin
  private void resizeLayout(boolean backToNormalSize){
    FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) circleFrameLayout.getLayoutParams();

    ViewTreeObserver vto = circleFrameLayout.getViewTreeObserver();
    vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            circleFrameLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            circleRadius = circleFrameLayout.getMeasuredWidth();
        }
    });

    if (backToNormalSize) {
        params.width = WRAP_CONTENT;
        params.height = WRAP_CONTENT;
        params.topMargin = 0;

    } else {
        params.topMargin = (int) (circleRadius * 0.3);
        params.height = circleRadius - circleRadius / 3;
        params.width = circleRadius - circleRadius / 3;
    }

    circleFrameLayout.setLayoutParams(params);
  }

}

布局文件,其中图钉位于屏幕中央:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/map_container"
         android:layout_width="match_parent"
         android:layout_height="match_parent">

<fragment 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="com.example.mapstest.MapsActivity" />

<FrameLayout
    android:id="@+id/pin_view_line"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_marginTop="@dimen/line_top_margin"
    android:background="@drawable/line_background"/>

<FrameLayout
    android:id="@+id/pin_view_circle"
    android:layout_gravity="center"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/circle_background">

    <TextView
        android:id="@+id/textView"
        android:layout_margin="@dimen/inner_circle_margin"
        android:layout_width="@dimen/inner_circle_radius"
        android:layout_height="@dimen/inner_circle_radius"
        android:layout_gravity="top|center_horizontal"
        android:gravity="center"
        android:text="12 min"
        android:textSize="@dimen/text_size"
        android:textColor="@android:color/white"/>

    <ProgressBar
        android:id="@+id/profile_loader"
        android:layout_margin="@dimen/inner_circle_margin"
        android:layout_width="@dimen/inner_circle_radius"
        android:layout_height="@dimen/inner_circle_radius"
        android:indeterminate="true"
        android:layout_gravity="top|center_horizontal"
        android:visibility="gone"
        android:contentDescription="@null"/>

</FrameLayout>

不移动时圈出背景:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
   android:shape="oval">    
<solid android:color="@android:color/holo_green_dark"/>
<stroke
    android:width="@dimen/stroke_width"
    android:color="@android:color/black"/>
<size
    android:width="@dimen/circle_radius"
    android:height="@dimen/circle_radius"/>
</shape>

地图移动时圈出背景:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
   android:shape="oval">    
<solid android:color="@android:color/black"/>
<size
    android:width="@dimen/circle_radius"
    android:height="@dimen/circle_radius"/>
</shape>

行背景文件:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
   android:shape="rectangle">    
<solid android:color="@android:color/black"/>
<size
    android:width="@dimen/line_width"
    android:height="@dimen/line_height"/>
</shape>

尺寸:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <dimen name="circle_radius">48dp</dimen>
  <dimen name="line_width">4dp</dimen>
  <dimen name="line_height">40dp</dimen>
  <dimen name="stroke_width">4dp</dimen>
  <dimen name="text_size">10sp</dimen>
  <dimen name="inner_circle_radius">40dp</dimen>
  <dimen name="inner_circle_margin">4dp</dimen>
  <dimen name="line_top_margin">20dp</dimen>
</resources>

我希望它对您有所帮助,但如果您有任何问题可以随意提出,或者您是否看到了哪些方面需要改进 - 请编辑我的解决方案。

干杯。

答案 1 :(得分:5)

将布局放在FrameLayout中并在Map上绘制图片。 当GoogleMap准备就绪时(我的代码使用RxJava):

Observable.<Void>create(subscriber -> {
        mMap.setOnCameraIdleListener(() -> subscriber.onNext(null));
    })
            .debounce(1, TimeUnit.SECONDS)
            .subscribeOn(AndroidSchedulers.mainThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(aVoid -> {
                LatLng newPos = mMap.getProjection().fromScreenLocation(new Point(mBinding.googleMap.getWidth() / 2, mBinding.googleMap.getHeight() / 2));

                makeServerRequest(newPos);
            });

答案 2 :(得分:1)

布局

标记应位于地图上的特定坐标处。因此,当您更改地图时,它们会移动。

由于您的图钉始终位于地图的中间,因此不适合使用Marker创建它。相反,您可以将它放在地图片段的中心位于地图容器的中心。因此,您的XML应如下所示:

<RelativeLayout>
  <fragment 
    android:id="@+id/map_fragment" />

  <RelativeLayout
    android:id="@+id/pin_view"
    android:centerInParent="true" />
</RelativeLayout>

您可以将儿童添加到pin_view,以根据您的要求实施动画。

Pin States

根据您提供的GIF,引脚可以有三种状态。

  • 装载
  • 加载

监听

您可以通过设置这些侦听器来触发动画:

  • setOnCameraMoveStartedListener
    • 以前的值需要无效。将PIN的状态更改为Empty
    • 取消任何正在进行的请求
  • setOnCameraIdleListener
    • 使用map.getCameraPosition()
    • 获取坐标
    • 将图钉的状态更改为“正在加载”
    • 触发网络调用以获取数据。在回调中
      • 将针脚状态更改为“已加载”状态&#39;并显示该值 请注意,如果用户在api完成之前移动,回调将无法执行,因为我们将在用户移动后立即取消请求。因此,这种情况也将得到照顾