设为首页 收藏本站
查看: 757|回复: 0

[经验分享] Surface Dial 与 Windows Wheel UWP应用开发

[复制链接]

尚未签到

发表于 2017-6-29 08:02:48 | 显示全部楼层 |阅读模式
  随着微软发布 Surface Studio 在演示视频中非常抢眼的一个配件就是 Surface Dial,Dial 是Windows输入设备大家庭中的新成员我们把它归类为Windows Wheel 类型设备。今天为大家介绍一下如何配合这个神奇设备开发自己的应用。
DSC0000.png

  Dial 是一个类似于滚轮的设备,可以协助用户更快的想计算机输入信息,但是Dial并不是一个专为精准输入所设计的设备,换句话说如果用户想点击屏幕上某一个点我们还是推荐用户使用手指触摸或者Surface Pan 或者鼠标完成这项工作,Dial更适合类似于画布的旋转,笔触的选择等快速的操作。
DSC0001.png

  Surface Dial操作非常简单,只有三个操作事件 长按单击,以及 转动并且如果Surface Dial 与 Surface Studio 一起使用的话 Surface Dial 的菜单可以使用 Surface Dial的屏幕菜单,就是将 Dial 放在 Surface Studio 屏幕上随后通过对Surface Dial的操作,围绕Dial的屏幕周围会出现一个菜单。
DSC0002.png

  Dial 自身与windows衔接紧密并且内置系统工具例如调整系统音量,大小缩小,以及撤销从做等功能。此外Dial 与 Windows Ink集成也是非常紧密。如果您的WUP应用已经使用了 InkCanvas 和 InkToolbar 那么 Dial就会自动和 InkToolbar中的内容相结合例如 调整标尺的角度和调整笔触的大小等功能。
DSC0003.png

  然而对于我们开发者而言 Surface 也是为我们提供了API(这里分别有UWP 和 Win32版本,本文着重介绍UWP版本),其实开发起来也是非常简单。
  首先关键点
  RadialController 类,通过CreateForCurrentView()静态方法获取实例。
  RadialControllerMenuItem 类,用来自定义菜单内容。当Dial长按时会弹出自定义菜单。
  ButtonClicked 事件,用来捕捉Dial的点击事件。
  RotationChanged 事件,用来捕捉Dial旋转事件。
  ScreenContactStarted 事件,捕捉 Dial 放在了 Surface Studio 上事件,并且可以从回调参数中获取Dial在屏幕中摆放的位置。
  ScreenContactContinued 事件,捕捉 Dial 放在了 Surface Studio 上并且移动了位置,并且可以从回调参数中获取Dial在屏幕中摆放的位置。
  ScreenContactEnded 事件,捕捉 Dial 从 Surface Studio 上移开事件。
  ControlLost 事件,捕捉操作的焦点离开。
  照搬一个MSDN上的demo code比较直观的展示这几个事件的用法以及如何判断Dial在Surface Studio上的位置
  Xaml代码



<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="HeaderPanel"
Orientation="Horizontal"
Grid.Row="0">
<TextBlock x:Name="Header"
Text="RadialController customization sample"
VerticalAlignment="Center"
Style="{ThemeResource HeaderTextBlockStyle}"
Margin="10,0,0,0" />
</StackPanel>
<Grid Grid.Row="1" x:Name="RootGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid x:Name="Grid0"
Grid.Row="0"
Grid.Column="0">
<StackPanel Orientation="Vertical"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<!-- Slider for rotational input -->
<Slider x:Name="RotationSlider0"
Width="300"
HorizontalAlignment="Left"/>
<!-- Switch for button input -->
<ToggleSwitch x:Name="ButtonToggle0"
HorizontalAlignment="Left"/>
</StackPanel>
</Grid>
<Grid x:Name="Grid1"
Grid.Row="0"
Grid.Column="1">
<StackPanel Orientation="Vertical"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<!-- Slider for rotational input -->
<Slider x:Name="RotationSlider1"
Width="300"
HorizontalAlignment="Left"/>
<!-- Switch for button input -->
<ToggleSwitch x:Name="ButtonToggle1"
HorizontalAlignment="Left"/>
</StackPanel>
</Grid>
<Grid x:Name="Grid2"
Grid.Row="1"
Grid.Column="0">
<StackPanel Orientation="Vertical"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<!-- Slider for rotational input -->
<Slider x:Name="RotationSlider2"
Width="300"
HorizontalAlignment="Left"/>
<!-- Switch for button input -->
<ToggleSwitch x:Name="ButtonToggle2"
HorizontalAlignment="Left"/>
</StackPanel>
</Grid>
<Grid x:Name="Grid3"
Grid.Row="1"
Grid.Column="1">
<StackPanel Orientation="Vertical"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<!-- Slider for rotational input -->
<Slider x:Name="RotationSlider3"
Width="300"
HorizontalAlignment="Left"/>
<!-- Switch for button input -->
<ToggleSwitch x:Name="ButtonToggle3"
HorizontalAlignment="Left"/>
</StackPanel>
</Grid>
</Grid>
</Grid>
  code-behind 代码



Slider ActiveSlider;
ToggleSwitch ActiveSwitch;
Grid ActiveGrid;
public MainPage()
{
...
myController.ScreenContactStarted +=
MyController_ScreenContactStarted;
myController.ScreenContactContinued +=
MyController_ScreenContactContinued;
myController.ScreenContactEnded +=
MyController_ScreenContactEnded;
myController.ControlLost += MyController_ControlLost;
//Set initial grid for Surface Dial input.
ActiveGrid = Grid0;
ActiveSlider = RotationSlider0;
ActiveSwitch = ButtonToggle0;
}
private void MyController_ScreenContactStarted(RadialController sender,
RadialControllerScreenContactStartedEventArgs args)
{
//find grid at contact location, update visuals, selection
  ActivateGridAtLocation(args.Contact.Position);
}
private void MyController_ScreenContactContinued(RadialController sender,
RadialControllerScreenContactContinuedEventArgs args)
{
//if a new grid is under contact location, update visuals, selection
if (!VisualTreeHelper.FindElementsInHostCoordinates(
args.Contact.Position, RootGrid).Contains(ActiveGrid))
{
ActiveGrid.Background = new
SolidColorBrush(Windows.UI.Colors.White);
ActivateGridAtLocation(args.Contact.Position);
}
}
private void MyController_ScreenContactEnded(RadialController sender, object args)
{
//return grid color to normal when contact leaves screen
ActiveGrid.Background = new
SolidColorBrush(Windows.UI.Colors.White);
}
private void MyController_ControlLost(RadialController sender, object args)
{
//return grid color to normal when focus lost
ActiveGrid.Background = new
SolidColorBrush(Windows.UI.Colors.White);
}
private void ActivateGridAtLocation(Point Location)
{
var elementsAtContactLocation =
VisualTreeHelper.FindElementsInHostCoordinates(Location,
RootGrid);
foreach (UIElement element in elementsAtContactLocation)
{
if (element as Grid == Grid0)
{
ActiveSlider = RotationSlider0;
ActiveSwitch = ButtonToggle0;
ActiveGrid = Grid0;
ActiveGrid.Background = new SolidColorBrush(
Windows.UI.Colors.LightGoldenrodYellow);
return;
}
else if (element as Grid == Grid1)
{
ActiveSlider = RotationSlider1;
ActiveSwitch = ButtonToggle1;
ActiveGrid = Grid1;
ActiveGrid.Background = new SolidColorBrush(
Windows.UI.Colors.LightGoldenrodYellow);
return;
}
else if (element as Grid == Grid2)
{
ActiveSlider = RotationSlider2;
ActiveSwitch = ButtonToggle2;
ActiveGrid = Grid2;
ActiveGrid.Background = new SolidColorBrush(
Windows.UI.Colors.LightGoldenrodYellow);
return;
}
else if (element as Grid == Grid3)
{
ActiveSlider = RotationSlider3;
ActiveSwitch = ButtonToggle3;
ActiveGrid = Grid3;
ActiveGrid.Background = new SolidColorBrush(
Windows.UI.Colors.LightGoldenrodYellow);
return;
}
}
}
  当然还有一个关键点如何创建自定义的菜单 使用Controller.Menu.Items.Add()方法添加和使用 Remove()方法删除自定义菜单。
  注意:这里Surface Dial 菜单可以容纳7个选项,如果超过7个那么Dial 需要有浮动控件配合选择,这样做会影响用户体验是不推荐的。



        private void CreateMenuItems()
{
menuItems = new List<RadialControllerMenuItem>
{
RadialControllerMenuItem.CreateFromKnownIcon("Item0", RadialControllerMenuKnownIcon.InkColor),
RadialControllerMenuItem.CreateFromKnownIcon("Item1", RadialControllerMenuKnownIcon.NextPreviousTrack),
RadialControllerMenuItem.CreateFromKnownIcon("Item2", RadialControllerMenuKnownIcon.Volume),
RadialControllerMenuItem.CreateFromIcon("Item3", RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/Item3.png"))),
RadialControllerMenuItem.CreateFromIcon("Item4", RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/Item4.png"))),
RadialControllerMenuItem.CreateFromIcon("Item5", RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/Item5.png")))
};
sliders = new List<Slider> { Slider0, Slider1, Slider2, Slider3, Slider4, Slider5 };
toggles = new List<ToggleSwitch> { Toggle0, Toggle1, Toggle2, Toggle3, Toggle4, Toggle5 };
for (int i = 0; i < menuItems.Count; ++i)
{
RadialControllerMenuItem radialControllerItem = menuItems;
int index = i;
radialControllerItem.Invoked += (sender, args) => { OnItemInvoked(index); };
}
}
private void OnItemInvoked(int selectedItemIndex)
{
activeItemIndex = selectedItemIndex;
}
private void AddItem(object sender, RoutedEventArgs e)
{
RadialControllerMenuItem radialControllerMenuItem = GetRadialControllerMenuItemFromSender(sender);
if (!Controller.Menu.Items.Contains(radialControllerMenuItem))
{
Controller.Menu.Items.Add(radialControllerMenuItem);
}
}
private void RemoveItem(object sender, RoutedEventArgs e)
{
RadialControllerMenuItem radialControllerMenuItem = GetRadialControllerMenuItemFromSender(sender);
if (Controller.Menu.Items.Contains(radialControllerMenuItem))
{
Controller.Menu.Items.Remove(radialControllerMenuItem);
}
}
private void SelectItem(object sender, RoutedEventArgs e)
{
RadialControllerMenuItem radialControllerMenuItem = GetRadialControllerMenuItemFromSender(sender);
if (Controller.Menu.Items.Contains(radialControllerMenuItem))
{
Controller.Menu.SelectMenuItem(radialControllerMenuItem);
PrintSelectedItem();
}
}
  菜单选项推荐使用64x64像素的PNG透明图像即可,但是同时支持到44x44的最小像素值。
  注意:黑色边框是为了在高对比度模式下也可以让我们的图标也可以清晰可见。
DSC0004.png

DSC0005.png

  最后附上微软的示例代码:RadialControlle
  希望上的总结可以帮助到大家, 同时欢迎大家在这里和我沟通交流或者在新浪微博上 @王博_Nick

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-389174-1-1.html 上篇帖子: [Windows驱动开发](四)内存管理 下篇帖子: 如何用dat批处理文件关闭某端口对应程序-Windows自动化命令
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表