通通玩blend美工(5)——旋转木马,交互性设计
这一篇偏向于逻辑的比较多,放在这个系列里会不会欠妥呢?在中国交互性设计也是美工的份内职责哦~
所以没有blend基础的人也可以看懂这篇文章,不过要用到初中的几何知识哦~亲
相信很多人都在手机或者网页上或者KTV的点歌系统里看到过旋转木马的目录导航,这个是如何做的呢??
最终效果如下:(貌似有点太大了显示不下,附加个阅览地址:
http://space.silverlightchina.net/ltt147/TTcarousel/Default.html)
(特别鸣谢烤地瓜的答疑,和地瓜村众人的热心帮助)
1.总体思路
分析上面效果:一排方块在转圈,点击的块跑到最近的位置
圈:其实就是一个椭圆,只不过人的近大远小的逻辑思维,大脑根据常识把它装换成了一个空间。
最近的位置:其实就是椭圆的最下面,块变得最大,所以感觉最近。
2.设计过程
首先我们来实现让这堆块围绕成一个椭圆。
step.1 椭圆是这样来产生滴~!↓
我以我微薄的几何知识用blend画出了上图,右上角看到我们久违的椭圆公式。第一个公式当把y单独提到等号一边时发现是要开根号的这样,就如图所看到的,一个x对应着两个y值还得去判断正负号显得麻烦了,就用第二个公式吧。其中a为x半轴,b为y半轴,d为角度。只需要一个角度d就可以确定出这个椭圆中的所有点了。
首先写出变换块位置的方法:
private void SetPosition(Grid item, double degree)
{
TransformGroup myTG = item.RenderTransform as TransformGroup;
TranslateTransform myTT = myTG.Children[] as TranslateTransform;//位置变换
myTT.X = a * Math.Cos(degree);//计算x坐标
myTT.Y = b * Math.Sin(degree);//计算y坐标
item.Tag = degree;
ScaleTransform myST = myTG.Children[1] as ScaleTransform;//大小变换
myST.ScaleX = myST.ScaleY = (1 - scale) / b * myTT.Y + scale;
Canvas.SetZIndex(item, (int)(myTT.Y + 2 * b));//层次变换为Y轴的位置
}
step.2 跟随鼠转标起来吧
这样传入需要变换的块和事先计算的该块的位置所在就角度就可以确定该块的位置、大小、层次了。单mousemove的时候,只要给每一个块都重新定位,把鼠标的移动距离装换为块组需要旋转的角度。
private void LayoutRoot_MouseMove(object sender, MouseEventArgs e)//鼠标移动时转动
{
if (isPress)//如果当前为按住鼠标的状态
{
foreach (Grid item in LayoutRoot.Children)//遍历所有的Grid
{
SetPosition(item, (double)item.Tag + (startPoint.X - e.GetPosition(this).X) * 0.005);//变换位置
}
startPoint.X = e.GetPosition(this).X;//把但前位置赋给开始位置
}
}
我把每个Grid的Tag用来存储自己当前所在的角度。
step.3 点击就转到前面来啊,亲~
接下来制作点击块转动的动画,即点击块后更具该块所在的位置,计算出旋转到90'时需要旋转的角度,然后所有块都转这个角度(为什么是90°呢?应该是270°啊~因为wpf中的位移动画,Y轴移动向下是为正,向上为负,这样就刚好和我们课堂上通用的坐标系刚好上下翻转了)
void newGrid_MouseUp(object sender, MouseButtonEventArgs e)//单击其中一块转正
{
double nowAngle = (double)((sender as Grid).Tag);//根据当前的块的角度
double needAngle = Math.PI / - nowAngle % (Math.PI * );//换算出把改块转正整体需要转动的角度
foreach (Grid item in LayoutRoot.Children)//为每一个块都添加动画
{
degree = (double)item.Tag;//获取各个块的角度
TransformGroup myTG = item.RenderTransform as TransformGroup;
TranslateTransform myTT = myTG.Children[] as TranslateTransform;//位置变换
Storyboard sb = new Storyboard();
sb.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
DoubleAnimation xAnimation = new DoubleAnimation();
xAnimation.To = a * Math.Cos(degree + needAngle);//计算x坐标
xAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
sb.Children.Add(xAnimation);
Storyboard.SetTarget(xAnimation, myTT);
Storyboard.SetTargetProperty(xAnimation, new PropertyPath("X"));
DoubleAnimation yAnimation = new DoubleAnimation();
yAnimation.To = b * Math.Sin(degree + needAngle);//计算x坐标
yAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
sb.Children.Add(yAnimation);
Storyboard.SetTarget(yAnimation, myTT);
Storyboard.SetTargetProperty(yAnimation, new PropertyPath("Y"));
ScaleTransform myST = myTG.Children[] as ScaleTransform;//大小变换
DoubleAnimation xScaleAnimation = new DoubleAnimation();
DoubleAnimation yScaleAnimation = new DoubleAnimation();
xScaleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
yScaleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
if (LayoutRoot.Children.IndexOf(item) == )//只添加一次动画完成后遍历控件改变位置
{
yScaleAnimation.Completed += new EventHandler((s, events) =>//动画结束后把整体的位置调整为动画结束时的位置
{
foreach (Grid item1 in LayoutRoot.Children)
{
SetPosition(item1, (double)item1.Tag);
}
});
}
yScaleAnimation.To = xScaleAnimation.To = ( - scale) / b * yAnimation.To + scale;
sb.Children.Add(xScaleAnimation);
Storyboard.SetTarget(xScaleAnimation, myST);
Storyboard.SetTargetProperty(xScaleAnimation, new PropertyPath("ScaleX"));
sb.Children.Add(yScaleAnimation);
Storyboard.SetTarget(yScaleAnimation, myST);
Storyboard.SetTargetProperty(yScaleAnimation, new PropertyPath("ScaleY"));
sb.Begin();//开始动画
item.Tag = degree + needAngle;//记录最后的角度
}
}
step.4 最靠近下面的要自动对正哦~
OK,接下来还差最有一点就是自动对正了,即当拖动时把最接近最近位置的块自定定位到最近。
原理就是遍历所有块的但前位置,角度越接近90°的就模拟一下它的单击
private void LayoutRoot_MouseUp(object sender, MouseButtonEventArgs e)//当鼠标弹起时判断最近的块,自动转正
{
double minNear = ;
Grid nearGrid = null;
foreach (Grid item in LayoutRoot.Children)//找出最近的Grid
{
double near = Math.Abs(Math.PI / - (double)item.Tag % (Math.PI * ));
if (near < minNear)
{
minNear = near;
nearGrid = item;
}
}
newGrid_MouseUp(nearGrid, null);//模拟最近的块被点了一次
isPress = false;
}
做完收工。
下面是我修改左上角的参数实现的几个比较好看的效果
效率也是很不错的,上面的100个块在我i7的电脑上一点都不卡哦。
大家如果调出什么好看的效果可以贴到回复里,交流下。
我把核心代码都讲了遍,如果还是有不懂的,可以给我留言。当然了这个silverlight版只是作为演示用得第一版,有很多细节方面我没处理。至于源码,因为我做的这个原版是WPF程序作为商用,所以经过多番考虑我还是不公布源码了。当然了我是不会告诉你可以反编译.xap来获取源码的。
通通玩blend美工(5)——旋转木马,交互性设计的更多相关文章
- 通通玩blend美工(6)上——仿iPhone滚动选择器的ListBox(UI设计)
原文:通通玩blend美工(6)上--仿iPhone滚动选择器的ListBox(UI设计) 好久没更新博客了,由于项目比较紧,期间收到不少园友的短消息,感谢大家对我的支持~~. 相信各位都在自己的神机 ...
- 通通玩blend美工(6)下——仿iPhone滚动选择器的ListBox(交互逻辑)
原文:通通玩blend美工(6)下--仿iPhone滚动选择器的ListBox(交互逻辑) 上一篇我们已经把界面画出来了,这篇我们就来制作交互的逻辑吧.上一篇的电梯: http://www.cnblo ...
- 通通玩blend美工(2)——时钟
原文:通通玩blend美工(2)--时钟 谢谢大家对我上一篇Blend的支持:通通玩blend美工(1)——荧光Button 再接再厉再来一篇~~! 这篇是建立在已经看得懂上一篇为基础来写的,有些细节 ...
- 通通玩blend美工(7)——简约而不简单的块
原文:通通玩blend美工(7)--简约而不简单的块 最近在研发一个WPF快速开发框架,满脑子都是各种逻辑各种模式,写一篇比较休闲娱乐的博客,宣泄下我对美工的热爱. 我一直以来有意无意在手机应用或者各 ...
- 通通玩blend美工(3)——可爱的云
原文:通通玩blend美工(3)--可爱的云 好久没有写这个系列的博客了,这里给个电梯吧,照顾新来的同学~~ 通通玩blend美工(1)——荧光Button 通通玩blend美工(2)——时钟 目前我 ...
- 通通玩blend美工(1)——荧光Button
原文:通通玩blend美工(1)--荧光Button 最近老大出差去了,光做项目也有点烦,写点教程消遣消遣(注:此乃初级教程,所以第一个消遣是本人消遣,第二个是指供各位看官消遣...) 看着各位大虾出 ...
- 通通玩blend美工(8)——动态绘制路径动画,画出个萌妹子~
原文:通通玩blend美工(8)--动态绘制路径动画,画出个萌妹子~ 2年前我在玩Flex的时候就一直有一个疑问,就是如何来实现一个蚊香慢慢烧完的Loading动画呢? 刚经历了某甲方高强度一个月的洗 ...
- 没有美工一样可以获取设计各种各样的UI图
没有美工一样可以获取设计各种各样的UI图 http://www.iconfont.cn
- 通通WPF随笔(1)——基于lucene.NET让ComboBox拥有强大的下拉联想功能
原文:通通WPF随笔(1)--基于lucene.NET让ComboBox拥有强大的下拉联想功能 我一直很疑惑百度.谷哥搜索框的下拉联想功能是怎么实现的?是不断地查询数据库吗?其实到现在我也不知道,他们 ...
随机推荐
- centos7安装nginx的两种方法
第一种方式:通过yum安装 直接通过 yum install nginx 肯定是不行的,因为yum没有nginx,所以首先把 nginx 的源加入 yum 中 运行下面的命令: 1.将nginx放到y ...
- javaScript基本事件
点击事件: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <tit ...
- [tmux] Create collections of panes using tmux windows
In tmux, a window is a collection of panes. Creating multiple windows is a great way to organize you ...
- CSDN code使用教程之git使用方法具体解释
首先须要下载GITclient.http://git-scm.com/downloads. . . 然后再code.csdn.net上面创建一个项目,假设 你的项目已经存在.那么请建立项目 ...
- DOM常用的四大对象是什么?
DOM常用的四大对象是什么? 一.总结 一句话总结: 1.关注结构,关注主干 2.从主干处着手的话,可以发现dom就是四个东西,document(文档),element,attribute,event ...
- Angular.js回想+学习笔记(1)【ng-app和ng-model】
Angular.js中index.html简单结构: <!doctype html> <html ng-app> <head> <script src=&qu ...
- [Ramda] Pick and Omit Properties from Objects Using Ramda
Sometimes you just need a subset of an object. In this lesson, we'll cover how you can accomplish th ...
- html常用属性border-radius、linear-gradient怎么使用
html常用属性border-radius.linear-gradient怎么使用 一.总结 一句话总结: 1.border-radius: 8px 8px 8px 8px !important; 2 ...
- SecondaryNameNode 的作用
Secondary NameNode:它究竟有什么作用? 尽量不要将 secondarynamede 和 namenode 放在同一台机器上. 1. NameNode NameNode 主要是用来保存 ...
- Notes on OpenSSL and Qt(ssl.pri,qsslocket_openssl_symbols.cpp)
Libraries name of openssl? The "library" portion of OpenSSL consists of two libraries. On ...