我将从一个显示正在发生的事情的gif开始。
列表项应该设置为标题项的动画。如您所见,当按下后退按钮时,标题项会向下设置动画以成为列表项。还有另一个问题,即这些片段的Activity父级也会在淡入淡出过渡后闪现,所以如果您对此有任何想法,我想知道:)
现在,在粘贴代码段之前,先解释一下我的代码。此应用程序导航HTML文档的树结构。小RecyclerView
个列表项是文档的标题。单击文档时,它会将标题固定在顶部,并显示一个显示HTML的WebView
。只有一个片段,当创建新片段时,该片段会创建自己的另一个实例。结构有点奇怪,但后退按钮和堆栈似乎应该工作。这段代码在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>
这是片段的主要布局。 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"/>
这是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);
}
}
}
RecyclerViewAdapater
。在这里,我为每个项目设置了TransitionName
。我已经检查过以确保转换名称在启动片段时匹配,并且在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;
}
这是整个OnCreateView
方法,可以很好地衡量。但我认为与我的过渡相关的唯一部分是
_selectedTitleView.TransitionName = "preview" + _selectedTitle;
_selectedTitleView.Text = _selectedTitle;
_selectedTitleView
是固定在顶部的TextView
。 _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);
}
}
。这是因为此片段的第一个实例顶部没有锚定文件,因此这些视图不可见。
public class PreviewTransition : TransitionSet
{
public PreviewTransition()
{
SetOrdering(TransitionOrdering.Together);
AddTransition(new ChangeTransform()).
AddTransition(new ChangeBounds());
}
}
这是单击列表项时执行的代码。
SubRoutineSelected
最后,这是动画的类。非常简单。
所以我希望SOMEBODY知道要查看的方向。我真的无法弄清楚为什么返回动画会起作用而不是开始动画。
只是为了澄清,这是两个不同片段之间的过渡。 OnCreateView
方法可被视为&#34; First Fragment&#34;,然后var socks = require('socksv5'),
SSHClient = require('ssh2').Client;
socks.connect({
host: 'ssh.example.org', // destination
port: 22,
proxyHost: '127.0.0.1',
proxyPort: 1080,
auths: [ socks.auth.None() ]
}, function(socket) {
var conn = new SSHClient();
conn.on('ready', function() {
conn.exec('uptime', function(err, stream) {
if (err) throw err;
stream.on('close', function(code, signal) {
conn.end();
}).on('data', function(data) {
console.log('STDOUT: ' + data);
}).stderr.on('data', function(data) {
console.log('STDERR: ' + data);
});
});
}).connect({
sock: socket,
username: 'frylock',
privateKey: require('fs').readFileSync('/here/is/my/key')
});
});
是&#34; Second Fragment&#34;。