共享元素的输入过渡不起作用,但返回过渡可以正常工作(片段过渡)

Jas*_*oms 5 android android-animation xamarin.android android-transitions shared-element-transition

我将从显示事件情况的gif图像开始。

发生的事情的GIF

该列表项应该设置为动画头文件。如您所见,当按下“后退”按钮时,标题项目会向下动画,成为列表项目。还有一个问题,这些片段的“活动”父对象也会在渐变过渡之后闪烁,因此,如果您对此有任何想法,我想知道:)

现在,在粘贴代码片段之前对我的代码进行一些解释。这个应用程式可浏览HTML文件的树状结构。小RecyclerView列表项是文档的标题。单击文档时,它会将标题固定在顶部,WebView并显示HTML。只有一个片段,并且在创建新片段时,该片段会创建其自身的另一个实例。该结构有些奇怪,但是后退按钮和堆栈似乎可以正常工作。这段代码在C#中,因为我使用的是Xamarin.Android,但除单击处理外,大多数代码都非常相似。

我可以从我的XML文件开始。布局仍然是WIP,所以我知道它们很凌乱。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/linear_layout_main"
    android:background="#ffffff">
  <LinearLayout
    android:id="@+id/progressLayout"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:visibility="gone"
    android:gravity="center">
    <ProgressBar
        android:id="@+id/progressbar"
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
  </LinearLayout>
  <LinearLayout
      android:id="@+id/subroutines_layout"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:gravity="center"
      android:orientation="vertical"
      android:background="#ffffff">
    <TextView
        android:id="@+id/routine_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:padding="5dp"
        android:textSize="24sp"
        android:visibility="gone"/>
    <FrameLayout
       android:id="@+id/preview_frame"
       android:layout_width ="match_parent"
       android:layout_height="150dp"
       android:visibility="gone">
      <WebView
        android:id="@+id/routine_preview"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:gravity="center_vertical"
        android:padding="5dp"
        android:transitionName="webview_preview_transition"
        android:scrollbars="none"
        android:visibility="gone"/>
      <TextView
        android:id="@+id/routine_preview_clickable"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:gravity="center_vertical"
        android:visibility="gone"/>
    </FrameLayout>
    <TextView
        android:id="@+id/preview_separator"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:gravity="center_vertical"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:background="@color/material_grey_100"
        android:visibility="gone"/>
    <android.support.v7.widget.RecyclerView
        android:id="@+id/routines_rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </android.support.v7.widget.RecyclerView>
  </LinearLayout>
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

这是片段的主要布局。该WebView是一个框架,由一个看不见的覆盖内TextView,因为我需要能够点击它扩大预览。

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/routines_rv_item"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="48dp"
    android:gravity="center_vertical"
    android:textSize="16sp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:background="@android:color/transparent"/>
Run Code Online (Sandbox Code Playgroud)

这是RecyclerView列表项。

namespace Routines.Views.Routines
{
    class RoutineAdapter : RecyclerViewAdapter<PublishedDocumentFragmentDTO>
    {
        public RoutineAdapter(List<PublishedDocumentFragmentDTO> items,
                                int layout,
                                Func<View, Action<int>, HolderBase> viewHolderInitializer)
            : base(items, layout, viewHolderInitializer) { }

        public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
        {
            var vh = (RoutineHolder)holder;
            vh.Text.Text = Items[position].Title;
            vh.Text.TransitionName = "preview" + Items[position].Title;
        }

        public void UpdateData(List<PublishedDocumentFragmentDTO> routines)
        {
            Items = routines;
        }
    }

    public class RoutineHolder : HolderBase
    {
        public TextView Text { get; private set; }

        public RoutineHolder(View itemView, Action<int> action) : base(itemView, action)
        {
            Text = itemView.FindViewById<TextView>(Resource.Id.routines_rv_item);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

RecyclerViewAdapater。在这里,我TransitionName为每个项目设置。我已经检查过以确保在启动片段和in时过渡名称匹配OnCreateView,因此我认为这不是问题。

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            var v = inflater.Inflate(Resource.Layout.routines_rv_fragment, container, false);

            _subRoutinesLayout = v.FindViewById<LinearLayout>(Resource.Id.subroutines_layout);
            _subRoutinesView = v.FindViewById<RecyclerView>(Resource.Id.routines_rv);
            _progressLayout = v.FindViewById<LinearLayout>(Resource.Id.progressLayout);
            _selectedTitleView = v.FindViewById<TextView>(Resource.Id.routine_title);
            _selectedPreview = v.FindViewById<WebView>(Resource.Id.routine_preview);
            _separator = v.FindViewById<TextView>(Resource.Id.preview_separator);
            _previewFrame = v.FindViewById<FrameLayout>(Resource.Id.preview_frame);
            _selectedPreviewClickable = v.FindViewById<TextView>(Resource.Id.routine_preview_clickable);

            _subRoutinesView.HasFixedSize = true;
            _subRoutinesView.SetLayoutManager(new LinearLayoutManager(Activity));
            _subRoutinesView.AddItemDecoration(new MaterialDesignDivider(Activity, Resource.Drawable.md_divider));

            _selectedPreview.TransitionGroup = true;

            if (!_topLevel)
            {

                _selectedTitleView.Visibility = ViewStates.Visible;
                _selectedPreview.Visibility = ViewStates.Visible;
                _separator.Visibility = ViewStates.Visible;
                _previewFrame.Visibility = ViewStates.Visible;
                _selectedPreviewClickable.Visibility = ViewStates.Visible;

                _selectedTitleView.TransitionName = "preview" + _selectedTitle;
                _selectedTitleView.Text = _selectedTitle;

                IRoutinesService _routinesService;
                var routinesContainer = AutoFac.Container;
                _routinesService = routinesContainer.Resolve<IRoutinesService>();

                var blobIdGuid = new Guid(_selectedBlobId);
                Tuple<bool, string> tuple = _routinesService.GetFragment(blobIdGuid);

                if (tuple.Item1)
                {
                    string mimeType = "text/html";
                    string encoding = "UTF-8";
                    string html = File.ReadAllText(tuple.Item2);

                    _selectedPreview.LoadDataWithBaseURL("", transformedHtml, mimeType, encoding, "");
                }

                _selectedPreviewClickable.Click += PreviewClicked;
            }

            return v;
        }
Run Code Online (Sandbox Code Playgroud)

这是整个OnCreateView方法,很好。但我认为与过渡有关的唯一部分是

        _selectedTitleView.TransitionName = "preview" + _selectedTitle;
        _selectedTitleView.Text = _selectedTitle;
Run Code Online (Sandbox Code Playgroud)

_selectedTitleViewTextView锚定在顶部的。 _selectedTitle将作为RecyclerView所选项目的标题传递到片段中。 _topLevel是从其自身创建此片段时bool设置的true。这是因为该片段的第一个实例在顶部没有锚定文件,因此这些视图不可见。

private void SubRoutineSelected(int position)
        {    
            PublishedDocumentFragmentDTO selectedRoutine;

            IRoutinesService _routinesService;
            var container = AutoFac.Container;
            _routinesService = container.Resolve<IRoutinesService>();

            if (_topLevel)
            {
                selectedRoutine = _viewModel.SelectedRoutineTree[position];
            }
            else
            {
                var childList = _viewModel.RetrieveSelectedChildren(_fragId, _viewModel.SelectedRoutineTree);
                selectedRoutine = childList[position];
            }

            var newFragId = selectedRoutine.FragmentId;
            var newBlobId = selectedRoutine.BlobId;
            var title = selectedRoutine.Title;

            if (selectedRoutine.Children.Any())
            {
                SubroutinesFragment selectedRoutineFragment = new SubroutinesFragment(_viewModel, newFragId, false, title, newBlobId);

                if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
                {
                    SharedElementReturnTransition = new PreviewTransition();
                    ExitTransition = new Fade();

                    selectedRoutineFragment.SharedElementEnterTransition = new PreviewTransition();
                    selectedRoutineFragment.EnterTransition = new Fade();

                }

                var test = (RoutineHolder)_subRoutinesView.FindViewHolderForAdapterPosition(position);

                FragmentManager.BeginTransaction().
                    Replace(Resource.Id.main_frame, selectedRoutineFragment).
                    AddToBackStack(null).
                    AddSharedElement(test.Text, test.Text.TransitionName).
                    Commit();
            }
            else
            {
                var intent = new Intent(Activity, typeof(RoutineActivity));
                intent.PutExtra(RoutineBundleKeys.BLOB_ID, newBlobId);
                intent.PutExtra(RoutineBundleKeys.ROUTINE_TITLE, title);
                StartActivity(intent);
            }
        }
Run Code Online (Sandbox Code Playgroud)

这是单击列表项时执行的代码。

public class PreviewTransition : TransitionSet
{
    public PreviewTransition()
    {
        SetOrdering(TransitionOrdering.Together);
        AddTransition(new ChangeTransform()).
            AddTransition(new ChangeBounds());
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,这是动画的类。很简单的。

因此,我希望SOMEBODY知道应朝哪个方向发展。我真的无法弄清楚为什么返回动画有效,但不能弄清楚起始动画为何。

为了澄清,这是两个不同片段之间的过渡。该SubRoutineSelected方法可以被认为是“第一个片段”,然后OnCreateView是“第二个片段”。