I'm trying to do a simple shared element transition where a row of the clicked list item transitions into the top header view of the resulting activity. I want the top header view to take the position of the list item, fade itself in, then transform to its final position.
This is the simple sharedElementEnterTransition that I wrote for the called activity:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<fade android:fadingMode="fade_out" />
<changeBounds />
<changeTransform />
<changeImageTransform />
</transitionSet>
However, the fade transition isn't doing anything. I see the resulting view suddenly pop up on the spot then transforms to the final position.
Here's where I start the activity
view.setOnClickListener(view -> {
final Intent intent = new Intent(...);
view.setTransitionName("test");
final ActivityOptions options =
ActivityOptions.makeSceneTransitionAnimation(activity, view, "test");
startActivity(intent, options.toBundle());
});
Can't quite figure out what's happening. Anyone has any ideas? The layout codes are exactly what you would expect with with android:transitionName="test".
Meanwhile debugging Visibility class, I figured out that target view was not the expected one, therefore I forced it to test it, and it seems working. However, I don't know if this is the perfect solution, because I also agreed that it should work as other transitions (automatically)
sharedElementEnterTransition = Fade(Visibility.MODE_IN).addTarget(your_view)
If you want a sequential transitions, you might need to create a TransitionSet and add it
val fadeIn = Fade(Visibility.MODE_IN).addTarget(your_view)
val move = TransitionInflater.from(context)
.inflateTransition(android.R.transition.move)
val transitionSet = TransitionSet().apply {
ordering = ORDERING_TOGETHER
addTransition(move)
addTransition(fadeIn)
}
sharedElementEnterTransition = transitionSet
Related
I have implements a mapbox MapView. It appears on screen just fine, but when I try to pan the map around, it kinds moves a few pixels on the screen in the direction I intended and then it stop while my finger is still sliding. Sometimes that would happen and sometimes it wouldn't respond at all.
When it stops, it doesn't mean it is stuck now - I can try again and it might move again but the same way.
It's very unpredictable, not consistent and clunky.
**I have to mention, that double click for zooming always works. So it's something with the swipe gesture that doesn't sit well.
I have the map hosted in a fragment and I show in in a frame inside another fragment. Could it have anything to do to the fact that it's two layers of fragment managers (fragment within fragment).
This is my map's fragment xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:mapbox="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.ImageMapViewFragment"
tools:showIn="#layout/fragment_image_expanded">
<com.mapbox.mapboxsdk.maps.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
mapbox:mapbox_cameraZoom="11"/>
</androidx.constraintlayout.widget.ConstraintLayout>
This is my fragment:
mapView = view.findViewById(co.getdere.R.id.mapView)
mapView?.getMapAsync { mapboxMap ->
mapboxMap.setStyle(Style.LIGHT) { style ->
style.addImage(
DERE_PIN,
BitmapUtils.getBitmapFromDrawable(resources.getDrawable(R.drawable.pin_icon))!!,
true
)
val geoJsonOptions = GeoJsonOptions().withTolerance(0.4f)
val symbolManager = SymbolManager(mapView!!, mapboxMap, style, null, geoJsonOptions)
symbolManager.iconAllowOverlap = true
sharedViewModelForImage.sharedImageObject.observe(this, Observer {
it?.let { image ->
val symbolOptions = SymbolOptions()
.withLatLng(LatLng(image.location[0], image.location[1]))
.withIconImage(DERE_PIN)
.withIconSize(1.3f)
.withZIndex(10)
.withDraggable(true)
symbolManager.create(symbolOptions)
val position = CameraPosition.Builder()
.target(LatLng(image.location[0], image.location[1]))
.zoom(10.0)
.build()
mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position))
}
})
}
}
These are my dependencies (the last I've added trying to solve my problem but it remains, that dependency didn't change anything really)
implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:7.4.0-alpha.1'
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-annotation-v7:0.6.0'
implementation 'com.mapbox.mapboxsdk:mapbox-android-gestures:0.4.0'
My problem was that even though my fragment was external, it was hosted inside a scroll layout so the gestures were lost between the two view probably
In my app m trying to implement shared element transition between listview name from one activity and Toolbar title in the next activity. The problem i am facing is that shared element is not animated as it should be instead its animated along with the entire layout enter and exit transitions.
gif animation
here the insurance text should animate separately from the entire animation.
Calling Activity animations are as follows:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setSharedElementReturnTransition(TransitionInflater.from(this)
.inflateTransition(R.transition.trans_move));
// getWindow().setSharedElementExitTransition(new TransitionSet()
// .addTransition(new Fade()));
Slide slideTransition = new Slide();
slideTransition.setSlideEdge(Gravity.LEFT);
slideTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
getWindow().setReenterTransition(slideTransition);
getWindow().setExitTransition(slideTransition);
}
setShareElementExitTransition has no effect on the transition so commented it out
Intent used for starting the second activity
ActivityOptionsCompat activityOptions
= ActivityOptionsCompat.makeSceneTransitionAnimation(
HomeActivity.this,
new Pair<>(view.findViewById(R.id.nameTextView),
SharedCertificatesActivity.ab_title)
);
Intent _intent=new Intent(mContext, SharedCertificatesActivity.class);
ActivityCompat.startActivity(HomeActivity.this,
_intent, activityOptions.toBundle());
The Second activity has the following scenes transitions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Re-enter transition is executed when returning to this activity
Slide slideTransition = new Slide();
slideTransition.setSlideEdge(Gravity.LEFT);
slideTransition.setDuration(getResources().getInteger(R.integer.anim_duration_medium));
Slide slideRightTransition = new Slide();
slideRightTransition.setSlideEdge(Gravity.RIGHT);
slideRightTransition.setDuration(getResources().getInteger(R.integer.anim_duration_medium));
// getWindow().setAllowReturnTransitionOverlap(true);
getWindow().setReenterTransition(slideRightTransition);
getWindow().setExitTransition(slideTransition);
// getWindow().setSharedElementEnterTransition(TransitionInflater.from(this)
// .inflateTransition(R.transition.trans_move));
ViewCompat.setTransitionName(title, ab_title);
}
i also found a similar problem here on SO but the solution mentioned there didn't work for me.
if its above problem then the layout for the second activity is as below:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="#color/primary"
app:popupTheme="#style/AppTheme.PopupOverlay">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:fontFamily="sans-serif-medium"
android:text="Binder Name"
android:textColor="#color/_kAppearanceUINavigationBarTextColor"
android:textSize="20sp" />
</android.support.v7.widget.Toolbar>
<include layout="#layout/binder" />
</LinearLayout>
.
.
.
</android.support.design.widget.CoordinatorLayout>
Any help would be highly appreciated
Resolved the issue
The issue was mainly due the animation timings issue. Shared element was animating much faster (default value) as compared to the other window animations. Changed the setupWindowAnimations method in the second activity as follows
private void setupWindowAnimations() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Slide slideTransition = new Slide();
slideTransition.setSlideEdge(Gravity.LEFT);
slideTransition.setInterpolator(new DecelerateInterpolator());
slideTransition.setDuration(460);
Slide slideRightTransition = new Slide();
slideRightTransition.setSlideEdge(Gravity.RIGHT);
slideRightTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
getWindow().setReenterTransition(slideRightTransition);
getWindow().setExitTransition(slideTransition);
getWindow().setEnterTransition(slideTransition);
getWindow().setSharedElementEnterTransition(new ChangeBounds().setDuration(450));
getWindow().setSharedElementReturnTransition(null);
ViewCompat.setTransitionName(title, ab_title);
ViewCompat.setTransitionName(menu1, fab_anim);
}
}
Now is more smooth and the shared element transition as per the expected result. Credit goes to guides.codepath.com and George Mount blog for clearing out more about shared element transitions.
Note: There is google bug for returning back the shared element textview back to the calling activity which is till date not resolved. so had to disable the shared element return transition from the calling activity.
I have a shared element transition when a `RecyclerView item click starts a detail Activity, but the ripple effect on the item click is never visible
Start Activity with shared element transition
Intent intent = IntentUtils.createDetailsIntent(InspectionListFragment.this.getContext(), record);
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(),
view, getString(R.string.transition_element)).toBundle();
getActivity().startActivity(intent, options);
I noticed this log message
D/OpenGLRenderer: endAllStagingAnimators on 0x95e86600 (RippleDrawable) with handle 0xaa6c2760
If I remove the transition, the ripple works (and I don't see this message).
Delay Activity start using Handler
If I use a Handler with postDelayed to start the Activity, the results were mixed. I see the ripple, but the transition is not as smooth:
handler.postDelayed(new Runnable() {
#Override
public void run() {
Intent intent = IntentUtils.createDetailsIntent(InspectionListFragment.this.getContext(), record);
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(),
view, getString(R.string.transition_element)).toBundle();
getActivity().startActivity(intent, options);
}
}, 200);
Using ListView
Note that using a ListView with the same item layout and makeSceneTransitionAnimation works fine. Unfortunately this is not suitable.
The item layout
<LinearLayout
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
I ran into the same issue when I had an ImageView within the card as the shared element. I was able to resolve it by using the CardView as the source view for the shared element transition (and the ripple effect) instead.
<android.support.v7.widget.CardView
android:id="#+id/itemCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardCornerRadius="#dimen/card_corner_radius"
app:cardElevation="#dimen/card_elevation"
android:layout_gravity="center"
android:clickable="true"
android:onClick="#{onItemClick}"
android:foreground="?android:attr/selectableItemBackground"
>
I'm using data binding, but the shared element change was essentially just selecting a different source view:
// before:
//onItemClickListener.onItemClick(view, getAdapterPosition(), getItemId(), Pair.create((View)b.itemImage, "activity_image"));
// after:
onItemClickListener.onItemClick(view, getAdapterPosition(), getItemId(), Pair.create((View)b.itemCard, "activity_image"));
Before this, I also tried using postDelayed with a short delay, but I found that approach added too much delay to the navigation for my liking.
I'm trying to set up a "close to start" button in a game. The game takes the user from view to view like a maze. The user could be on any view, but I want a way to get them back to the start screen. Is there a way to find and return the ID of the current view for my findViewByID? I've found a I've tried the following code in various forms:
OnClickListener closetomain = new OnClickListener() {
#Override
public void onClick(View v) {
int currentid = v.findFocus().getId();
RelativeLayout hideme = (RelativeLayout)findViewById(currentid);
hideme.setVisibility(View.GONE);
setContentView(R.layout.main);
// RelativeLayout showme = (RelativeLayout)findViewById(R.id.startLayout);
// showme.setVisibility(View.VISIBLE);
}
};
Okay, it turns out I should have given each close button the same ID and used theisenp's suggestion for the simplest code (well, that I could understand). It also turns out that I should have started by putting each level/layout in its own activity. You live and you learn I guess. Below is my XML and java. It may not be the elegant solution but I'm not sure I care all that much as long as it works.
<ImageButton android:id="#+id/closeButton"
android:layout_height="wrap_content"
android:background="#drawable/close"
android:layout_width="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="10dp"
android:layout_marginBottom="10dp"
android:onClick="closetomain">
</ImageButton>
And here's my Java:
public void closetomain(View view) {
switch(view.getId()) {
case R.id.closeButton:
setContentView(R.layout.main);
break;
}
}
Why do you need to retrieve the id of the current view? Is it just so that you can set it's visibility to GONE? If so, there are probably better ways of implementing that same functionality.
Instead of just changing the layout with setContentView(), it would probably be a better idea to have the Start Screen be its own separate activity. When you are in any of the "maze views" you could simply use an intent to start your home screen activity like this
Intent startScreenIntent = new Intent(this, StartScreen.Class);
startActivity(startScreenIntent);
Then you won't have to worry about finding id's or changing visibilities, plus the code is cleaner, because it separates the code for your Maze levels and your Start Menu.
What I would like to accomplish is to, at runtime, place a button in the middle of the screen, as the very top layer, overlaying anything below it. (It's not big, so it will not completely cover the screen, just whatever happens to be below it.)
I looked at creating a custom dialog, however that blocks all other user input. I want all of the views below this new button to act normally and respond to the user, but I just want to add (and later remove) the button above everything.
Hopefully that makes sense. I'm just wondering what might be the best approach to look into?
Use a FrameLayout, with the button as it's 2nd child. Set it to GONE when you don't want it visible.
I had to overlay a simple layout programmatically on top of any visible activity. Normal activity layout xmls don't know anything about the overlay. Layout had one textview component but could have any structure you see fit. This is my overlay layout.
res/layout/identity.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/identitylayout"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" >
<TextView
android:id="#+id/identityview"
android:padding="5dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textColor="#FFFFFF" android:background="#FF6600"
android:textSize="30dp"
/>
</RelativeLayout>
Overlay is shown on top of the existing content, after timeout is deleted from the screen. Application calls this function to display overlay.
private void showIdentity(String tag, long duration) {
// default text with ${xx} placeholder variables
String desc = getString(R.string.identity);
desc = desc.replace("${id}", reqId!=null ? reqId : "RequestId not found" );
desc = desc.replace("${tag}", tag!=null ? tag : "" );
desc = desc.trim();
// get parent and overlay layouts, use inflator to parse
// layout.xml to view component. Reuse existing instance if one is found.
ViewGroup parent = (ViewGroup)findViewById(R.id.mainlayout);
View identity = findViewById(R.id.identitylayout);
if (identity==null) {
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
identity = inflater.inflate(R.layout.identity, parent, false);
parent.addView(identity);
}
TextView text = (TextView)identity.findViewById(R.id.identityview);
text.setText(desc);
identity.bringToFront();
// use timer to hide after timeout, make sure there's only
// one instance in a message queue.
Runnable identityTask = new Runnable(){
#Override public void run() {
View identity = findViewById(R.id.identitylayout);
if (identity!=null)
((ViewGroup)identity.getParent()).removeView(identity);
}
};
messageHandler.removeCallbacksAndMessages("identitytask");
messageHandler.postAtTime(identityTask, "identitytask", SystemClock.uptimeMillis()+duration);
}
Timer messageHandler is member of main Activity instance (private Handler messageHandler) where I put all scheduled tasks. I am using Android 4.1 device lower than that I don't know what happens.