android - intent - shared element transition dialog
¿Cómo puedo escalar vistas de texto usando transiciones de elementos compartidos? (4)
Editar:
Como señaló Kiryl Tkach en los comentarios a continuación, hay una mejor solución descrita en esta charla de Google I / O.
Puede crear una transición personalizada que anima el tamaño del texto de un TextView
de la siguiente manera:
public class TextSizeTransition extends Transition {
private static final String PROPNAME_TEXT_SIZE = "alexjlockwood:transition:textsize";
private static final String[] TRANSITION_PROPERTIES = { PROPNAME_TEXT_SIZE };
private static final Property<TextView, Float> TEXT_SIZE_PROPERTY =
new Property<TextView, Float>(Float.class, "textSize") {
@Override
public Float get(TextView textView) {
return textView.getTextSize();
}
@Override
public void set(TextView textView, Float textSizePixels) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePixels);
}
};
public TextSizeTransition() {
}
public TextSizeTransition(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public String[] getTransitionProperties() {
return TRANSITION_PROPERTIES;
}
@Override
public void captureStartValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
@Override
public void captureEndValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
private void captureValues(TransitionValues transitionValues) {
if (transitionValues.view instanceof TextView) {
TextView textView = (TextView) transitionValues.view;
transitionValues.values.put(PROPNAME_TEXT_SIZE, textView.getTextSize());
}
}
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
if (startValues == null || endValues == null) {
return null;
}
Float startSize = (Float) startValues.values.get(PROPNAME_TEXT_SIZE);
Float endSize = (Float) endValues.values.get(PROPNAME_TEXT_SIZE);
if (startSize == null || endSize == null ||
startSize.floatValue() == endSize.floatValue()) {
return null;
}
TextView view = (TextView) endValues.view;
view.setTextSize(TypedValue.COMPLEX_UNIT_PX, startSize);
return ObjectAnimator.ofFloat(view, TEXT_SIZE_PROPERTY, startSize, endSize);
}
}
Dado que cambiar el tamaño del texto de TextView
hará que sus límites de diseño cambien durante el curso de la animación, hacer que la transición funcione correctamente requerirá un poco más de esfuerzo que simplemente lanzar una transición ChangeBounds
al mismo TransitionSet
. En su lugar, lo que deberá hacer es medir / diseñar manualmente la vista en su estado final en un SharedElementCallback
.
He publicado un proyecto de ejemplo en GitHub que ilustra el concepto (tenga en cuenta que el proyecto define dos sabores de productos Gradle ... uno usa Transiciones de actividad y el otro usa Transiciones de fragmentos).
Puedo obtener TextViews para hacer la transición perfecta entre dos actividades usando ActivityOptions.makeSceneTransitionAnimation
. Sin embargo, quiero hacer que el texto se amplíe a medida que las transiciones. Puedo ver el ejemplo de diseño del material ampliando el texto "Alphonso Engelking" en la transición de la tarjeta de contacto.
He intentado establecer los atributos de escala en el TextView de destino y usar las transiciones de elementos compartidos changeTransform, pero no se escala y el texto termina siendo truncado a medida que las transiciones.
¿Cómo puedo escalar las vistas de texto usando la transición de elementos compartidos?
Esto fue cubierto en una de las charlas de Google I / O 2016 . La fuente de la transición que puede copiar en su código se encuentra here . Si su IDE se queja del addTarget(TextView.class);
requiere API 21, simplemente elimine el constructor y agregue el objetivo dinámicamente o en su xml.
es decir (nota esto es en Kotlin)
val textResizeTransition = TextResize().addTarget(view.findViewById(R.id.text_view))
Si observa cómo funciona ChangeBounds
, funciona en las propiedades izquierda / derecha / superior / inferior de la vista.
Lo que espero es que deberá usar el mismo tamaño de texto en las dos actividades y usar las propiedades scaleX
y scaleY
en su actividad iniciada para modificar el tamaño del texto según sea necesario. Luego, use una combinación de ChangeBounds
y ChangeTransform
en su TransitionSet
.
Utilicé la solución de Alex Lockwood y simplifiqué el uso (solo para TextSize de TextView), espero que esto ayude:
public class Activity2 extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity2);
EnterSharedElementTextSizeHandler handler = new EnterSharedElementTextSizeHandler(this);
handler.addTextViewSizeResource((TextView) findViewById(R.id.timer),
R.dimen.small_text_size, R.dimen.large_text_size);
}
}
y la clase EnterSharedElementTextSizeHandler:
public class EnterSharedElementTextSizeHandler extends SharedElementCallback {
private final TransitionSet mTransitionSet;
private final Activity mActivity;
public Map<TextView, Pair<Integer, Integer>> textViewList = new HashMap<>();
public EnterSharedElementTextSizeHandler(Activity activity) {
mActivity = activity;
Transition transitionWindow = activity.getWindow().getSharedElementEnterTransition();
if (!(transitionWindow instanceof TransitionSet)) {
mTransitionSet = new TransitionSet();
mTransitionSet.addTransition(transitionWindow);
} else {
mTransitionSet = (TransitionSet) transitionWindow;
}
activity.setEnterSharedElementCallback(this);
}
public void addTextViewSizeResource(TextView tv, int sizeBegin, int sizeEnd) {
Resources res = mActivity.getResources();
addTextView(tv,
res.getDimensionPixelSize(sizeBegin),
res.getDimensionPixelSize(sizeEnd));
}
public void addTextView(TextView tv, int sizeBegin, int sizeEnd) {
Transition textSize = new TextSizeTransition();
textSize.addTarget(tv.getId());
textSize.addTarget(tv.getText().toString());
mTransitionSet.addTransition(textSize);
textViewList.put(tv, new Pair<>(sizeBegin, sizeEnd));
}
@Override
public void onSharedElementStart(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {
for (View v : sharedElements) {
if (!textViewList.containsKey(v)) {
continue;
}
((TextView) v).setTextSize(TypedValue.COMPLEX_UNIT_PX, textViewList.get(v).first);
}
}
@Override
public void onSharedElementEnd(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {
for (View v : sharedElements) {
if (!textViewList.containsKey(v)) {
continue;
}
TextView textView = (TextView) v;
// Record the TextView''s old width/height.
int oldWidth = textView.getMeasuredWidth();
int oldHeight = textView.getMeasuredHeight();
// Setup the TextView''s end values.
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textViewList.get(v).second);
// Re-measure the TextView (since the text size has changed).
int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
textView.measure(widthSpec, heightSpec);
// Record the TextView''s new width/height.
int newWidth = textView.getMeasuredWidth();
int newHeight = textView.getMeasuredHeight();
// Layout the TextView in the center of its container, accounting for its new width/height.
int widthDiff = newWidth - oldWidth;
int heightDiff = newHeight - oldHeight;
textView.layout(textView.getLeft() - widthDiff / 2, textView.getTop() - heightDiff / 2,
textView.getRight() + widthDiff / 2, textView.getBottom() + heightDiff / 2);
}
}
}