当前位置: 首页 > 知识库问答 >
问题:

如何使用共享元素转换缩放文本视图?

常智勇
2023-03-14

我能够使用ActivityOptions让文本视图在两个活动之间完美过渡。MakeScenetTransitionAnimation。不过,我想让文本在转换时放大。我可以看到材料设计示例在名片转换中放大了文本“Alphonso Engelking”。

我尝试在目标TextView上设置缩放属性,并使用ChangeTransform共享元素转换,但它不缩放,文本在转换时最终被截断。

如何使用共享元素转换缩放文本视图?

共有3个答案

巴博耘
2023-03-14

这在2016年的谷歌I/O会谈中有所涉及。可以复制到代码中的转换的源代码可以在这里找到。如果你的IDE抱怨addTarget(TextView.class)需要API 21,只需删除构造函数并动态或在xml中添加目标即可。

i、 e.(注意这是在科特林)

val textResizeTransition = TextResize().addTarget(view.findViewById(R.id.text_view))
祁通
2023-03-14

我使用了Alex Lockwood的解决方案,并简化了使用(仅适用于TextView的TextSize),我希望这将有助于:

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);
    }
}

和类EngSharedElementTextSizeHandler:

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);
        }
    }
}
邓卓
2023-03-14

正如Kiryl Tkach在下面的评论中指出的,在这次谷歌I/O对话中,有一个更好的解决方案。

您可以创建一个自定义过渡,以设置文本视图文本大小的动画,如下所示:

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);
    }
}

由于更改TextView的文本大小会导致其布局边界在动画过程中发生变化,因此要使转换正常工作,需要比简单地将ChangeBounds转换放入同一个transition中多一点努力。您需要做的是在SharedElementCallback中手动测量/布局处于结束状态的视图。

我在GitHub上发布了一个示例项目,说明了这个概念(请注意,该项目定义了两种Gradle产品风格……一种使用活动转换,另一种使用片段转换)。

 类似资料:
  • 我尝试使用和都没有用,因为它们同时拉动整个轴,并且不允许输入左右两个参数。我唯一能想到的就是使用3D转换和透视,但我不能让它工作。 我试过的可怕的例子:https://codepend.io/fortypercentitanium/pen/yznleor

  • 我一直在尝试实现这个共享元素转换,并在单击转换时不断出现“java.lang.IllegalArgumentException:共享元素不能为null”错误。请帮忙。 这是下面给出的MainActive onCreate方法。请检查我的代码。 这是recyclerView的onClickListener。 图像的过渡名称相同。这里的bug修复在使用共享元素的活动转换中出现问题并不是问题所在。 我卡

  • 我正在实现一个gallery应用程序,它有一个片段,其中包含一个带有图像的RecyclerView,单击一个图像,我会转到ViewPager循环浏览图像 目前,我正试图实现像本视频中那样的入门动画。问题是动画不起作用,我显然遗漏了一些东西(只是显示与转换相关的代码): 查看页面: GridAdapter: 在MainActivity中,我在onClick中实例化ViewPagerFragment:

  • 我在两个活动之间有一个非常简单的过渡,有时,图像停在中间,滞后,闪烁黑色。 我已经在Glide中多次使用共享元素转换,但这次我不能让它不延迟。 这是第一个活动: 这是第二个活动: 这是第二个活动的布局: 约束布局 这是动画: 这很简单,但我无法理解它。第二个图像最初有一些侦听器使用手势,我认为这就是原因,但注释所有内容仍然会滞后。第一个活动中的图像是另一个具有相同转换名称的共享元素转换的目标,这可

  • 请看这段显示共享元素活动转换的视频。这是从列表活动到详细信息活动的过渡。 [视频链接不再工作] 如您所见,imageview绘制在选项卡前面。 我所期望的是选项卡在imageview上以字体绘制,并在整个转换过程中淡出(以便在动画结束时它们消失)。 唯一有效的方法是将设置为true,但这会产生其他不好的效果,因此这似乎不是一个选项。 最常见的建议方法是在转换本身中包含选项卡,但问题是选项卡不在详细

  • 我在Lollipop上的共享元素转换中看到了奇怪的事情。共享元素在开始动画之前闪烁(请看视频https://www.youtube.com/watch?v=DCoyyC_S-9A) 我不知道为什么会这样。但是,当我添加