Xamarin - ConvertFormsToNative 函数不是 return Spotlight 中的真正原生元素
Xamarin - ConvertFormsToNative function doesn't return the real native element in Spotlight
我想在我的应用程序中实现 Spotlight 功能,如 Spotlight library is Android specific and I didn't knew how to access platform specific libraries from the core Forms project, @Jason recommended to use DependencyService and @Colex - MSFT helped in its 。有一些小东西没有按预期工作。
我基本上有这 3 个按钮(第一个在左上角,第二个在右上角,第三个在底部中心)。
线条动画必须从组件(按钮)开始,就像 Spotlight 库中的 Preview 一样,但在我的应用程序中它们是从左上角开始的(所有这些).
我希望当第一个按钮的聚光灯淡出时,第二个按钮的聚光灯应该淡入,当它淡出时,第三个按钮的聚光灯应该淡入。
但是现在发生的情况是,当第一个按钮的聚光灯淡出时,第二个按钮的聚光灯已经淡入(已经启用),因此没有动画(行从组件(按钮)开始并且文本出现)。
Droid\Control\SpotLightService.cs
[assembly: Xamarin.Forms.Dependency(typeof(SpotLightService))]
namespace CustomRenderer.Droid.Control
{
public class SpotLightService : ISpotLight
{
private bool isRevealEnabled_FirstButton_SpotLight = true;
private bool isRevealEnabled_SecondButton_SpotLight = true;
private bool isRevealEnabled_ThirdButton_SpotLight = true;
private SpotlightView FirstButton_SpotLight;
private SpotlightView SecondButton_SpotLight;
private SpotlightView ThirdButton_SpotLight;
public void ShowSpotLight_FirstButton(Xamarin.Forms.View view, string usageId)
{
FirstButton_SpotLight = new SpotlightView.Builder(MainActivity.Instance)
.IntroAnimationDuration(400)
.EnableRevealAnimation(isRevealEnabled_FirstButton_SpotLight)
.PerformClick(true)
.FadeinTextDuration(400)
.HeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.HeadingTvSize(32)
.HeadingTvText("First Button")
.SubHeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.SubHeadingTvSize(16)
.SubHeadingTvText("Lorem ipsum dolor sit amet, consectetur adipiscing elit")
.MaskColor(Android.Graphics.Color.ParseColor("#dc000000"))
.Target(ConvertFormsToNative(view))
.LineAnimDuration(400)
.LineAndArcColor(Android.Graphics.Color.ParseColor("#eb273f"))
.DismissOnTouch(true)
.DismissOnBackPress(true)
.EnableDismissAfterShown(true)
.UsageId(usageId)
.ShowTargetArc(true)
.Show();
}
public void ShowSpotLight_SecondButton(Xamarin.Forms.View view, string usageId)
{
SecondButton_SpotLight = new SpotlightView.Builder(MainActivity.Instance)
.IntroAnimationDuration(400)
.EnableRevealAnimation(isRevealEnabled_SecondButton_SpotLight)
.PerformClick(true)
.FadeinTextDuration(400)
.HeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.HeadingTvSize(32)
.HeadingTvText("Second Button")
.SubHeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.SubHeadingTvSize(16)
.SubHeadingTvText("Sed do eiusmod tempor incididunt ut labore eta")
.MaskColor(Android.Graphics.Color.ParseColor("#dc000000"))
.Target(ConvertFormsToNative(view))
.LineAnimDuration(400)
.LineAndArcColor(Android.Graphics.Color.ParseColor("#eb273f"))
.DismissOnTouch(true)
.DismissOnBackPress(true)
.EnableDismissAfterShown(true)
.UsageId(usageId)
.ShowTargetArc(true)
.Show();
}
public void ShowSpotLight_ThirdButton(Xamarin.Forms.View view, string usageId)
{
ThirdButton_SpotLight = new SpotlightView.Builder(MainActivity.Instance)
.IntroAnimationDuration(400)
.EnableRevealAnimation(isRevealEnabled_ThirdButton_SpotLight)
.PerformClick(true)
.FadeinTextDuration(400)
.HeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.HeadingTvSize(32)
.HeadingTvText("Third Button")
.SubHeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.SubHeadingTvSize(16)
.SubHeadingTvText("Ut enim ad minim veniam, quis nostrud exercitation")
.MaskColor(Android.Graphics.Color.ParseColor("#dc000000"))
.Target(ConvertFormsToNative(view))
.LineAnimDuration(400)
.LineAndArcColor(Android.Graphics.Color.ParseColor("#eb273f"))
.DismissOnTouch(true)
.DismissOnBackPress(true)
.EnableDismissAfterShown(true)
.UsageId(usageId)
.ShowTargetArc(true)
.Show();
}
public View ConvertFormsToNative(Xamarin.Forms.View view)
{
var vRenderer = Platform.CreateRendererWithContext(view, MainActivity.Instance);
var Androidview = vRenderer.View;
vRenderer.Tracker.UpdateLayout();
var size = view.Bounds;
var layoutParams = new ViewGroup.LayoutParams((int)size.Width, (int)size.Height);
Androidview.LayoutParameters = layoutParams;
view.Layout(size);
Androidview.Layout((int)size.X, (int)size.Y, (int)view.WidthRequest, (int)view.HeightRequest);
Androidview.SetBackgroundColor(Android.Graphics.Color.Red);
return Androidview;
}
}
}
MainPage.xml.cs
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
LayoutChanged += FirstButton_SpotLight;
LayoutChanged += SecondButton_SpotLight;
LayoutChanged += ThirdButton_SpotLight;
}
bool isShown_FirstButton_SpotLight = false;
private void FirstButton_SpotLight(object sender, EventArgs e)
{
if (!isShown_FirstButton_SpotLight)
{
DependencyService.Get<ISpotLight>().ShowSpotLight_FirstButton(FirstButton, "FirstButton");
isShown_FirstButton_SpotLight = true;
}
}
bool isShown_SecondButton_SpotLight = false;
private void SecondButton_SpotLight(object sender, EventArgs e)
{
if (!isShown_SecondButton_SpotLight)
{
DependencyService.Get<ISpotLight>().ShowSpotLight_SecondButton(SecondButton, "SecondButton");
isShown_SecondButton_SpotLight = true;
}
}
bool isShown_ThirdButton_SpotLight = false;
private void ThirdButton_SpotLight(object sender, EventArgs e)
{
if (!isShown_ThirdButton_SpotLight)
{
DependencyService.Get<ISpotLight>().ShowSpotLight_ThirdButton(ThirdButton, "ThirdButton");
isShown_ThirdButton_SpotLight = true;
}
}
}
正如 json 提到的,我意识到这是真的,函数 ConvertFormsToNative
不是 return 真正的原生元素。
满足您要求的唯一解决方法是
为整个 Page
创建自定义渲染器,并在 native(android) 项目中添加控件。
详情可参考Customizing a ContentPage.
- 为页面创建自定义渲染器。
[assembly: ExportRenderer(typeof(Page1), typeof(MainPageRenderer))]
namespace CustomRenderer.Droid
{
class MainPageRenderer : PageRenderer
{
private Android.Views.View view;
private Android.Widget.Button button1;
private Android.Widget.Button button2;
private Android.Widget.Button button3;
public MainPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
{
return;
}
view = MainActivity.Instance.LayoutInflater.Inflate(Resource.Layout.MyPage, this, false);
AddView(view);
view.Click += View_Click;
button1 = view.FindViewById<Android.Widget.Button>(Resource.Id.firstButton);
button2 = view.FindViewById<Android.Widget.Button>(Resource.Id.secondButton);
button3 = view.FindViewById<Android.Widget.Button>(Resource.Id.thirdButton);
}
bool isShown_FirstButton_SpotLight = false;
bool isShown_SecondButton_SpotLight = false;
bool isShown_ThirdButton_SpotLight = false;
private void View_Click(object sender, EventArgs e)
{
if (!isShown_FirstButton_SpotLight)
{
show(button1 ,"First Button" ,"Lorem ipsum dolor sit amet, consectetur adipiscing elit", "FirstButton");
isShown_FirstButton_SpotLight = true;
return;
}
if (!isShown_SecondButton_SpotLight)
{
show(button2,"Second Button", "Sed do eiusmod tempor incididunt ut labore eta", "SecondButton");
isShown_SecondButton_SpotLight = true;
return;
}
if (!isShown_ThirdButton_SpotLight)
{
show(button3,"Third Button", "Ut enim ad minim veniam, quis nostrud exercitation", "ThirdButton");
isShown_ThirdButton_SpotLight = true;
return;
}
}
void show(Android.Views.View view, string title, string subTitle, string usageId)
{
new SpotlightView.Builder(MainActivity.Instance)
.IntroAnimationDuration(400)
.EnableRevealAnimation(true)
.PerformClick(true)
.FadeinTextDuration(400)
.HeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.HeadingTvSize(32)
.HeadingTvText(title)
.SubHeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.SubHeadingTvSize(16)
.SubHeadingTvText(subTitle)
.MaskColor(Android.Graphics.Color.ParseColor("#dc000000"))
.Target(view)
.LineAnimDuration(400)
.LineAndArcColor(Android.Graphics.Color.ParseColor("#eb273f"))
.DismissOnTouch(true)
.DismissOnBackPress(true)
.EnableDismissAfterShown(true)
.UsageId(usageId)
.ShowTargetArc(true)
.Show();
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
var msw = MeasureSpec.MakeMeasureSpec(r - l, MeasureSpecMode.Exactly);
var msh = MeasureSpec.MakeMeasureSpec(b - t, MeasureSpecMode.Exactly);
view.Measure(msw, msh);
view.Layout(0, 0, r - l, b - t);
}
}
}
- 创建一个 xml 并将其放在 android 项目的文件夹
Resources/layout
中。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/firstButton"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="50dp"
android:layout_marginTop="50dp"
android:text="First"
android:background="#00ff00"/>
<Button
android:id="@+id/secondButton"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="100dp"
android:layout_marginTop="100dp"
android:text="Second"
android:background="#ff0000"/>
<Button
android:id="@+id/thirdButton"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="150dp"
android:layout_marginTop="150dp"
android:text="Third"
android:background="#0000ff"/>
</LinearLayout>
小东西
点击白色space区域依次显示Spotlight
插件只支持圆形聚光灯,你可以把控件做成圆形,勾选here。
我想在我的应用程序中实现 Spotlight 功能,如 Spotlight library is Android specific and I didn't knew how to access platform specific libraries from the core Forms project, @Jason recommended to use DependencyService and @Colex - MSFT helped in its
我基本上有这 3 个按钮(第一个在左上角,第二个在右上角,第三个在底部中心)。
线条动画必须从组件(按钮)开始,就像 Spotlight 库中的 Preview 一样,但在我的应用程序中它们是从左上角开始的(所有这些).
我希望当第一个按钮的聚光灯淡出时,第二个按钮的聚光灯应该淡入,当它淡出时,第三个按钮的聚光灯应该淡入。 但是现在发生的情况是,当第一个按钮的聚光灯淡出时,第二个按钮的聚光灯已经淡入(已经启用),因此没有动画(行从组件(按钮)开始并且文本出现)。
Droid\Control\SpotLightService.cs
[assembly: Xamarin.Forms.Dependency(typeof(SpotLightService))]
namespace CustomRenderer.Droid.Control
{
public class SpotLightService : ISpotLight
{
private bool isRevealEnabled_FirstButton_SpotLight = true;
private bool isRevealEnabled_SecondButton_SpotLight = true;
private bool isRevealEnabled_ThirdButton_SpotLight = true;
private SpotlightView FirstButton_SpotLight;
private SpotlightView SecondButton_SpotLight;
private SpotlightView ThirdButton_SpotLight;
public void ShowSpotLight_FirstButton(Xamarin.Forms.View view, string usageId)
{
FirstButton_SpotLight = new SpotlightView.Builder(MainActivity.Instance)
.IntroAnimationDuration(400)
.EnableRevealAnimation(isRevealEnabled_FirstButton_SpotLight)
.PerformClick(true)
.FadeinTextDuration(400)
.HeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.HeadingTvSize(32)
.HeadingTvText("First Button")
.SubHeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.SubHeadingTvSize(16)
.SubHeadingTvText("Lorem ipsum dolor sit amet, consectetur adipiscing elit")
.MaskColor(Android.Graphics.Color.ParseColor("#dc000000"))
.Target(ConvertFormsToNative(view))
.LineAnimDuration(400)
.LineAndArcColor(Android.Graphics.Color.ParseColor("#eb273f"))
.DismissOnTouch(true)
.DismissOnBackPress(true)
.EnableDismissAfterShown(true)
.UsageId(usageId)
.ShowTargetArc(true)
.Show();
}
public void ShowSpotLight_SecondButton(Xamarin.Forms.View view, string usageId)
{
SecondButton_SpotLight = new SpotlightView.Builder(MainActivity.Instance)
.IntroAnimationDuration(400)
.EnableRevealAnimation(isRevealEnabled_SecondButton_SpotLight)
.PerformClick(true)
.FadeinTextDuration(400)
.HeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.HeadingTvSize(32)
.HeadingTvText("Second Button")
.SubHeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.SubHeadingTvSize(16)
.SubHeadingTvText("Sed do eiusmod tempor incididunt ut labore eta")
.MaskColor(Android.Graphics.Color.ParseColor("#dc000000"))
.Target(ConvertFormsToNative(view))
.LineAnimDuration(400)
.LineAndArcColor(Android.Graphics.Color.ParseColor("#eb273f"))
.DismissOnTouch(true)
.DismissOnBackPress(true)
.EnableDismissAfterShown(true)
.UsageId(usageId)
.ShowTargetArc(true)
.Show();
}
public void ShowSpotLight_ThirdButton(Xamarin.Forms.View view, string usageId)
{
ThirdButton_SpotLight = new SpotlightView.Builder(MainActivity.Instance)
.IntroAnimationDuration(400)
.EnableRevealAnimation(isRevealEnabled_ThirdButton_SpotLight)
.PerformClick(true)
.FadeinTextDuration(400)
.HeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.HeadingTvSize(32)
.HeadingTvText("Third Button")
.SubHeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.SubHeadingTvSize(16)
.SubHeadingTvText("Ut enim ad minim veniam, quis nostrud exercitation")
.MaskColor(Android.Graphics.Color.ParseColor("#dc000000"))
.Target(ConvertFormsToNative(view))
.LineAnimDuration(400)
.LineAndArcColor(Android.Graphics.Color.ParseColor("#eb273f"))
.DismissOnTouch(true)
.DismissOnBackPress(true)
.EnableDismissAfterShown(true)
.UsageId(usageId)
.ShowTargetArc(true)
.Show();
}
public View ConvertFormsToNative(Xamarin.Forms.View view)
{
var vRenderer = Platform.CreateRendererWithContext(view, MainActivity.Instance);
var Androidview = vRenderer.View;
vRenderer.Tracker.UpdateLayout();
var size = view.Bounds;
var layoutParams = new ViewGroup.LayoutParams((int)size.Width, (int)size.Height);
Androidview.LayoutParameters = layoutParams;
view.Layout(size);
Androidview.Layout((int)size.X, (int)size.Y, (int)view.WidthRequest, (int)view.HeightRequest);
Androidview.SetBackgroundColor(Android.Graphics.Color.Red);
return Androidview;
}
}
}
MainPage.xml.cs
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
LayoutChanged += FirstButton_SpotLight;
LayoutChanged += SecondButton_SpotLight;
LayoutChanged += ThirdButton_SpotLight;
}
bool isShown_FirstButton_SpotLight = false;
private void FirstButton_SpotLight(object sender, EventArgs e)
{
if (!isShown_FirstButton_SpotLight)
{
DependencyService.Get<ISpotLight>().ShowSpotLight_FirstButton(FirstButton, "FirstButton");
isShown_FirstButton_SpotLight = true;
}
}
bool isShown_SecondButton_SpotLight = false;
private void SecondButton_SpotLight(object sender, EventArgs e)
{
if (!isShown_SecondButton_SpotLight)
{
DependencyService.Get<ISpotLight>().ShowSpotLight_SecondButton(SecondButton, "SecondButton");
isShown_SecondButton_SpotLight = true;
}
}
bool isShown_ThirdButton_SpotLight = false;
private void ThirdButton_SpotLight(object sender, EventArgs e)
{
if (!isShown_ThirdButton_SpotLight)
{
DependencyService.Get<ISpotLight>().ShowSpotLight_ThirdButton(ThirdButton, "ThirdButton");
isShown_ThirdButton_SpotLight = true;
}
}
}
正如 json 提到的,我意识到这是真的,函数 ConvertFormsToNative
不是 return 真正的原生元素。
满足您要求的唯一解决方法是
为整个 Page
创建自定义渲染器,并在 native(android) 项目中添加控件。
详情可参考Customizing a ContentPage.
- 为页面创建自定义渲染器。
[assembly: ExportRenderer(typeof(Page1), typeof(MainPageRenderer))]
namespace CustomRenderer.Droid
{
class MainPageRenderer : PageRenderer
{
private Android.Views.View view;
private Android.Widget.Button button1;
private Android.Widget.Button button2;
private Android.Widget.Button button3;
public MainPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
{
return;
}
view = MainActivity.Instance.LayoutInflater.Inflate(Resource.Layout.MyPage, this, false);
AddView(view);
view.Click += View_Click;
button1 = view.FindViewById<Android.Widget.Button>(Resource.Id.firstButton);
button2 = view.FindViewById<Android.Widget.Button>(Resource.Id.secondButton);
button3 = view.FindViewById<Android.Widget.Button>(Resource.Id.thirdButton);
}
bool isShown_FirstButton_SpotLight = false;
bool isShown_SecondButton_SpotLight = false;
bool isShown_ThirdButton_SpotLight = false;
private void View_Click(object sender, EventArgs e)
{
if (!isShown_FirstButton_SpotLight)
{
show(button1 ,"First Button" ,"Lorem ipsum dolor sit amet, consectetur adipiscing elit", "FirstButton");
isShown_FirstButton_SpotLight = true;
return;
}
if (!isShown_SecondButton_SpotLight)
{
show(button2,"Second Button", "Sed do eiusmod tempor incididunt ut labore eta", "SecondButton");
isShown_SecondButton_SpotLight = true;
return;
}
if (!isShown_ThirdButton_SpotLight)
{
show(button3,"Third Button", "Ut enim ad minim veniam, quis nostrud exercitation", "ThirdButton");
isShown_ThirdButton_SpotLight = true;
return;
}
}
void show(Android.Views.View view, string title, string subTitle, string usageId)
{
new SpotlightView.Builder(MainActivity.Instance)
.IntroAnimationDuration(400)
.EnableRevealAnimation(true)
.PerformClick(true)
.FadeinTextDuration(400)
.HeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.HeadingTvSize(32)
.HeadingTvText(title)
.SubHeadingTvColor(Android.Graphics.Color.ParseColor("#eb273f"))
.SubHeadingTvSize(16)
.SubHeadingTvText(subTitle)
.MaskColor(Android.Graphics.Color.ParseColor("#dc000000"))
.Target(view)
.LineAnimDuration(400)
.LineAndArcColor(Android.Graphics.Color.ParseColor("#eb273f"))
.DismissOnTouch(true)
.DismissOnBackPress(true)
.EnableDismissAfterShown(true)
.UsageId(usageId)
.ShowTargetArc(true)
.Show();
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
var msw = MeasureSpec.MakeMeasureSpec(r - l, MeasureSpecMode.Exactly);
var msh = MeasureSpec.MakeMeasureSpec(b - t, MeasureSpecMode.Exactly);
view.Measure(msw, msh);
view.Layout(0, 0, r - l, b - t);
}
}
}
- 创建一个 xml 并将其放在 android 项目的文件夹
Resources/layout
中。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/firstButton"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="50dp"
android:layout_marginTop="50dp"
android:text="First"
android:background="#00ff00"/>
<Button
android:id="@+id/secondButton"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="100dp"
android:layout_marginTop="100dp"
android:text="Second"
android:background="#ff0000"/>
<Button
android:id="@+id/thirdButton"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="150dp"
android:layout_marginTop="150dp"
android:text="Third"
android:background="#0000ff"/>
</LinearLayout>
小东西
点击白色space区域依次显示Spotlight
插件只支持圆形聚光灯,你可以把控件做成圆形,勾选here。