Créer Une Animation De Superposition D'ImageView Google Map
je suis en train de faire mon image de superposition pour faire des choses suivantes:
- onClick / onDrag de carte, afficher une image constante au milieu de la carte qui est un pin
- onTouchUp, changez l'image du marqueur en Marqueur de chargement et une fois les données chargement modifier le chargement de l'image à une nouvelle image avec du texte.
Voici une solution assez similaire à mon problème:
Ce que j'ai fait jusqu'à présent ?
- placé une imageview sur ma carte google au milieu , et a obtenu
loacation de l'imageView à l'aide de
mMap.getCameraPosition().target
qui donne des coordonnées approximatives de position moyenne en utilisantsetOnCameraChanged
, je sais que c'est déconseillé, bien mieux la solution?. - reste de la partie Je ne peux pas comprendre, bien que j'ai lu plusieurs questions disant qu'ils l'ont mis en œuvre enveloppant framelayout sur fragment de Google map, et en appliquant onTouch sur cela, mais ne peut pas trouver une réponse authentique pour celui-là aussi.
mon xml de fragment, où tout ce qui se passe ressemble à ceci :
<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 -->
Quelqu'un sait comment réaliser ce genre de comportement ?
3 réponses
la meilleure solution serait d'utiliser RxJava / RxAndroid et de faire des tâches de fond avec, mais je ne peux pas poster une solution en utilisant rx sans voir votre code et il y a déjà un exemple de @user27799 aussi @Manas Chaudhari a fourni une grande explication de la logique (ci-dessous).
//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);
}
}
fichier de mise en page avec pin au centre de l'écran:
<?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>
Encerclez l'arrière-plan lorsque ce n'est pas le cas déménagement:
<?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>
Cercle d'arrière-plan lorsque la carte est en mouvement:
<?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>
Ligne de fond de fichiers:
<?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>
Dimensions:
<?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>
j'espère que cela vous aide, mais si vous avez des questions n'hésitez pas à poser ou si vous voir les zones que vous amélioreriez - modifier ma solution.
Cheers.
vous mettre en page dans FrameLayout et dessiner une image sur la carte. Quand GoogleMap est prêt (mon code utilise 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);
});
Mise en page
les repères sont conçus pour être positionnés à des coordonnées précises sur la carte. Ainsi, ils se déplacent quand vous changez la carte.
comme votre NIP est toujours au milieu de la carte, il n'est pas approprié de le créer en utilisant Marker
. Au lieu de cela, vous pouvez le placer en dehors du fragment de carte au centre du conteneur de carte. Votre XML devrait donc ressembler à ceci:
<RelativeLayout>
<fragment
android:id="@+id/map_fragment" />
<RelativeLayout
android:id="@+id/pin_view"
android:centerInParent="true" />
</RelativeLayout>
Vous pouvez ajouter des enfants à pin_view
pour mettre en place des animations selon vos exigence.
États Pin
basé sur le gif fourni par vous, il peut y avoir trois états pour le NIP.
- Vide
- Chargement
- Chargé d'
Auditeurs
vous pouvez déclencher les animations en paramétrant ces écouteurs:
- setOnCameraMoveStartedListener
- valeur Précédente doit être invalidé. Changer l'état de pin en
Empty
- Annuler toutes les demandes en cours
- valeur Précédente doit être invalidé. Changer l'état de pin en
- setOnCameraIdleListener
- obtenir les coordonnées en utilisant
map.getCameraPosition()
- Modifier pin de l'état de "Chargement"
- Déclencher un appel réseau pour récupérer des données. Dans le rappel
- changer l'état du pin en 'Loaded' et afficher la valeur Notez que le callback ne sera pas exécuté, si l'utilisateur bouge avant que l'api ne soit terminée, car nous annulerons la requête dès que l'utilisateur déplacer. Donc, ce scénario sera également pris en charge
- obtenir les coordonnées en utilisant