Xamarin.iOS 波浪效果

以前Android写过一个demo,是波浪效果,应该是仿照百度外卖的那个头像效果。突然想拿Xamarin来试试,利用我的脑洞终于给弄出来了,不知道方法是不是合理。先贴出来展示一下吧.


实际效果是波浪在动,头像以及文字也在上下动,给人一种效果就是头像和文字是漂在波浪上面的。

下面来说一下实现吧:

首先将看见的这个view分成三个view,分别实现。第一个view就是波浪view,即如下图

就是类似一个正弦曲线的这么一个效果。

第二个就是头像加文字的view,把她单独出来做一个view目的就是可以单独控制它的动画来配合波浪的动画。


下面首先来看看波浪view的画法:新建一个View继承UIView。通过Draw方法来画线,想要实现波浪效果让它动起来,最少要画两个屏幕长度的波浪,这个大家应该能理解吧。

还有一点注意的就是我没有找到直接画正弦的方法,最后是用贝塞尔曲线拼接而成的。

看下代码:

using System;
using System.Drawing;
using CoreGraphics;
using UIKit;

namespace RuilaiGrow.iOS
{
	/// <summary>
	/// 波浪View
	/// by ge
	/// </summary>
	public class WaveView : UIView
	{

		//正线曲线,顶部,中线,底部Y轴高度
		private nfloat _waveTop = 50f;
		private nfloat _waveHalfHei = 65f;
		private nfloat _waveBottom = 80f;

		public WaveView()
		{
			this.Frame = new RectangleF(0, 0, (float)(UIScreen.MainScreen.Bounds.Width * 2), (float)_waveBottom);
			this.BackgroundColor = UIColor.White;
		}

		//划线
		public override void Draw(CoreGraphics.CGRect rect)
		{
			base.Draw(rect);

			//本View上半部分红色背景矩形
			CGContext contextBac = UIGraphics.GetCurrentContext();
			contextBac.SetFillColor(MvxTouchColor.DeepRed.CGColor);
			contextBac.AddRect(new RectangleF(0, 0, (float)(UIScreen.MainScreen.Bounds.Width * 2), (float)_waveHalfHei));
			contextBac.FillPath();
			//屏幕的宽度
			nfloat viewWid = UIScreen.MainScreen.Bounds.Width;

			//利用贝塞尔曲线完成正弦波浪曲线
			//分成两次画出正弦曲线
			for (int i = 0; i < 2; i++)
			{
				nfloat startX = i * viewWid;

				//左半边弧
				CGContext contextLeft = UIGraphics.GetCurrentContext();
				contextLeft.SetLineWidth(1f);
				contextLeft.SetStrokeColor(MvxTouchColor.DeepRed.CGColor);
				contextLeft.MoveTo(startX, _waveHalfHei);
				contextLeft.AddCurveToPoint(startX, _waveHalfHei,
										(startX + viewWid / 4), _waveTop,
											(startX + viewWid / 2), _waveHalfHei);
				contextLeft.SetFillColor(MvxTouchColor.White.CGColor);
				contextLeft.DrawPath(CGPathDrawingMode.EOFill);

				//右半边弧
				CGContext contextRight = UIGraphics.GetCurrentContext();
				contextRight.SetLineWidth(1f);
				contextRight.SetStrokeColor(MvxTouchColor.DeepRed.CGColor);
				contextRight.MoveTo((startX + viewWid / 2), _waveHalfHei);
				contextRight.AddCurveToPoint((startX + viewWid / 2),
										_waveHalfHei, (startX + (System.nfloat)(viewWid * 0.75)),
										_waveBottom, startX + viewWid, _waveHalfHei);
				contextRight.SetFillColor(MvxTouchColor.AlphaDeepRed.CGColor);
				contextRight.DrawPath(CGPathDrawingMode.EOFill);
			}
		}
	}
}

上面我将整个类都贴出来,因为没啥难度,不过有一点要注意的,就是在波浪下凹处仔细看会有一点透明白色的区域,这个区域我是将右半边弧度用了一个透明颜色填充了。大家可以自己换。

头像和文字的view我就不占用这里的地方了,没什么要注意的。

下面直接贴出来整体的View的类:

注:

1.代码中最下面部分就是波浪view与头像view的动画。波浪view还好说,就是一个循环左移的动画,头像的动画的轨迹分析一下:一个正弦函数移动,应该是先向下移动一个驼峰距离,在向上移动两个驼峰距离,在向下移动一个驼峰距离。这是一个完整的周期,下一个动画循环这个周期即可。

2.代码中使用了一种控件间的约束方式,大家可以换成自己的,如果需要的话可以私聊我。

3.动画属性我设置的是匀速的,即UIViewAnimationOptions.CurveLinear这里,相关属性大家查ios原生的就可以查到。

4.本人水平有限,可能用的都是特别简单的东西来实现这个功能,可能多走了些弯路或者有更好的实现方式,希望大家可以多多提建议,共同进步。

using System;
using System.Drawing;
using CoreGraphics;
using RuilaiGrow.iOS.Common;
using UIKit;

namespace RuilaiGrow.iOS
{
	/// <summary>
	/// 里程碑模块主页顶部头像View
	/// by ge
	/// </summary>
	public class UserHeaderView : UIView
	{

		private nfloat _waveBottom = 80f;
		private nfloat _waveTopHei = 7f;

		//波浪条
		private WaveView _waveView = null;
		public WaveView WaveView { 
			get {
				if (_waveView == null) {
					_waveView = new WaveView();
				}
				return _waveView;
			}
		}

		//头像,名字,年龄布局
		private UIView _headerView = null;
		public UIView HeaderView { 
			get {
				if (_headerView == null) {
					_headerView = new UIView();
					_headerView.AddSubview(HeaderImg);
					_headerView.AddSubview(NameText);
					_headerView.AddSubview(AgeText);
				}
				return _headerView;
			}
		}

		//头像
		private UIButton _headerImg = null;
		public UIButton HeaderImg { 
			get {
				if (_headerImg == null) {
					_headerImg = new UIButton();
					_headerImg.SetImage(UIImage.FromFile("icon_child_head.png"), UIControlState.Normal);
				}
				return _headerImg;
			}
		}

		//名字
		private UILabel _nameText = null;
		public UILabel NameText { 
			get {
				if (_nameText == null) {
					_nameText = new UILabel();
					_nameText.Text = "小贝";
					_nameText.TextAlignment = UITextAlignment.Left;
					_nameText.TextColor = MvxTouchColor.White;
					_nameText.Font = UIFont.SystemFontOfSize(18f);
					return _nameText;
				}
				return _nameText;
			}
		}

		//月龄
		private UILabel _ageText = null;
		public UILabel AgeText { 
			get {
				if (_ageText == null)
				{
					_ageText = new UILabel();
					_ageText.Text = "43个月";
					_ageText.TextAlignment = UITextAlignment.Left;
					_ageText.TextColor = MvxTouchColor.GraySix;
					_ageText.Font = UIFont.SystemFontOfSize(13f);
				}
				return _ageText;
			}
		}

		/// <summary>
		/// 构造函数
		/// 设定背景色与frame
		/// </summary>
		public UserHeaderView()
		{
			this.Frame = new RectangleF(0, 0, (float)UIScreen.MainScreen.Bounds.Width, (float)_waveBottom);
			this.BackgroundColor = UIColor.White;
		}

		//提交view
		public override void LayoutSubviews()
		{
			base.LayoutSubviews();

			nfloat textMarTop = 6f;
			nfloat marBottom = 6f;

			this.AddSubview(WaveView);
			this.AddSubview(HeaderView);

			//一种aotolayout方式进行view约束
			this.ConstrainLayout(() =>
			                     HeaderView.Frame.Bottom == this.Frame.Bottom - marBottom
			                     && HeaderView.Frame.Width == this.Frame.Width
			                     && HeaderView.Frame.Height == this.Frame.Height - marBottom
			                    );

			HeaderView.ConstrainLayout(() =>
										HeaderImg.Frame.Bottom == HeaderView.Frame.Bottom
										&& HeaderImg.Frame.GetCenterX() == HeaderView.Frame.GetCenterX()

			                           && NameText.Frame.Top == HeaderImg.Frame.Top + textMarTop
			                           && NameText.Frame.Left == HeaderImg.Frame.Right + textMarTop
			                           && NameText.Frame.Right == HeaderView.Frame.Right

			                           && AgeText.Frame.Top == NameText.Frame.Bottom
			                           && AgeText.Frame.Left == HeaderImg.Frame.Right + textMarTop
			                           && AgeText.Frame.Right == HeaderView.Frame.Right
									   );

			//开启动画
			startAnimation(UIScreen.MainScreen.Bounds.Width);
		}

		/// <summary>
		/// 开始波浪动画 动画结束监听中重启本方法
		/// </summary>
		/// <param name="leftMove">Left move.</param>
		public void startAnimation(nfloat leftMove)
		{
			startHeadAnimation(_waveTopHei, true);
			var waveFrame = WaveView.Frame;
			waveFrame.X = WaveView.Frame.X - leftMove;
			UIView.Animate(12d, 0d, UIViewAnimationOptions.CurveLinear, () => WaveView.Frame = waveFrame,
						   () =>
						   {
				
							   waveFrame.X = WaveView.Frame.X + leftMove;
							   WaveView.Frame = waveFrame;

							   /** 动画完成监听 **/
							   startAnimation(leftMove);
						   });
		}

		/// <summary>
		/// 头像初次view动画
		/// </summary>
		/// <param name="waveTopHei">Wave top hei.</param>
		public void startHeadAnimation(nfloat waveTopHei, bool isFirst)
		{
			var headerFrame = HeaderView.Frame;
			headerFrame.Y = HeaderView.Frame.Y + waveTopHei;
			UIView.Animate(3d, 0d, UIViewAnimationOptions.CurveLinear, () => HeaderView.Frame = headerFrame,
						   () =>
						   {
							   waveTopHei = waveTopHei * 2;
							   waveTopHei = -waveTopHei;

							   if (!isFirst)
							   		return;
				
							   /** 动画完成监听 **/
							   startHeadAnimationAgain(waveTopHei);
						   });
		}

		/// <summary>
		/// 头像view动画
		/// </summary>
		/// <param name="waveTopHei">Wave top hei.</param>
		public void startHeadAnimationAgain(nfloat waveTopHei)
		{
			var headerFrame = HeaderView.Frame;
			headerFrame.Y = HeaderView.Frame.Y + waveTopHei;
			UIView.Animate(6d, 0d, UIViewAnimationOptions.CurveLinear, () => HeaderView.Frame = headerFrame,
						   () =>
						   {
							   waveTopHei = waveTopHei / 2;
							   waveTopHei = -waveTopHei;

							   /** 动画完成监听 **/
						       startHeadAnimation(waveTopHei, false);
						   });
		}

	}
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值