【PersimmonUI柿饼学习营】基于柿饼UI仪表盘的制作--二牛哥

发布于 2018-09-17 00:03:54
    本帖最后由 二牛哥 于 2018-9-17 00:34 编辑



基于柿饼UI仪表盘的制作

前言: 本次的工作将完成两个目标,1 制作仪表盘APP, 2 接续上次帖子的内容将平板电脑UI增加一点新鲜元素,然后将仪表APP“装入”其中。为突出主题本文档分上、下篇分别描述。

上篇------制作仪表盘APP 一 目标:

通过PersimmonUI制作两个仪表盘,本例中可理解为汽车速度计和流量表(或电量表),仪表具有开关背光和指针控制功能。
二、方法: 1、 工具 设计好仪表效果图,通过PersimmonUI的画图控件------Canvas作为载体,采用系统API函数分别绘制仪盘盘面、指针、数字、环形渐变圆等元素将效果图中的各部件逐一呈现。
2、 算法 首先确定“盘面”所占弧度数量,然后确定弧度的始、终位置,接着根据刻度数量确定盘面弧度等分切割数量,最后根据三角函数结合笛卡尔直角坐标系可计算出指针的指向。
三、步骤:
1 建立工程并建立一个页面---page1(分辨率为800x480),分别拖动Canvas、Button控件
到页面按下图方式放置


1.png
设置Canvas控件属性------背景颜色为白色。分别设置4个按键的bindtap属性为onButtonA/B/C/D,控件字体hz16,文本为“开灯”、“关灯”、“加速”、“减速”。2 根据仪表效果图分别绘制弧段、刻度弧、指针、背光灯、背光弧,如下图所示(具体方法详见程序):
2.png
3 如法炮制,再绘制一个小仪表,如下图所示:
3.png
4 将大小仪表进行组合,如下图所示:4.png
6 编写按键功能函数,分别完成开灯、关灯、加速、减速功能,然后再将各种的功能函数与绘图代码填入各自的事件驱动函数中。
7 运行程序,验证功能
(1) 开关灯动画效果图
swLight.gif
(2) 加、减速效果图:GIF动画2(我制作动画的过程中出现了异常,未制作成功,稍后再贴)

8 关键代码:
var value1 = 0;
var value2 = 0;
var lightFlag = 0;


function OpenLight() { lightFlag = 1; };
function CloseLight(){ lightFlag = 0; };

function IncMeter1(){ if(value1<=178) value1+=2; };
function DecMeter1(){ if(value1>= 2) value1-=2; };

function IncMeter2(){ if(value2<=97.5) value2+=2.5; };
function DecMeter2(){ if(value2>= 2.5) value2-=2.5; };

function ResetValue(){ value1 = 0; value2 = 0; };
function SetValue2() { value2 = 100; };

var page = {



onLoad : function(e) {

//==========================================big meter=============================================


DecMeter1();
// CloseLight();

var context = pm.createCanvasContext('Canvas1', this) //获取画布对象
if (context)
{
var point = { x: 200, y: 200 }; //圆心坐标,相对于画布
var radius = 130; //半径
var start = -1.5 * Math.PI; //起始弧度

context.setLineWidth(30)
context.setStrokeStyle('#91C7AE')
context.setFillStyle('#91C7AE');

for( var i = 0; i <=9; i++ )
{
var stop = start + 0.15 * Math.PI ; //结束弧度
var x = Math.floor(110 * Math.cos(start)) + 200;
var y = Math.floor(110 * Math.sin(start)) + 200;
var v = 20 * i;

if (i >= 7)
context.fillText(v.toString(), x - 10, y);

else
context.fillText(v.toString(), x, y-3);

if (i == 9)
break;

context.beginPath(); //开始新的路径

context.arc( point.x, point.y, radius, start, stop - 0.003 * Math.PI, false); //画一段圆弧

context.stroke(); //填充路径

context.closePath(); //关闭路径
start = stop;

if (i == 2)
{
context.setStrokeStyle('rgba(255, 128, 0, 1)')//('#63869E')
context.setFillStyle('#63869E');
}
else if (i == 6)
{
context.setStrokeStyle('#C23531')
context.setFillStyle('#C23531');
}
}

//----------------------------------------------------//
//画背光弧
context.beginPath() //开始路径
context.setLineWidth(10)
if( lightFlag>0 ) context.setStrokeStyle( 'rgba(255, 0, 0, 1)');
else context.setStrokeStyle( 'rgba(0, 0, 0, 1)');
context.arc( point.x, point.y, 175, -1.5 * Math.PI, -0.15 * Math.PI, false);
context.stroke()
context.closePath();
//----------------------------------------------------
//画背光灯
// Create circular gradient
var grd = context.createCircularGradient(200, 200, 70)
if( lightFlag>0 ) grd.addColorStop(0, 'blue')
else grd.addColorStop(0, 'black')
grd.addColorStop(1, 'white')
context.beginPath()
// Fill with gradient
context.setFillStyle(grd)
context.fillRect(120,130, 150,150)
context.closePath();
//----------------------------------------------------\

radius = 150;
start = -1.5 * Math.PI;
context.setLineWidth(22)
context.setStrokeStyle('#91C7AE')
for( var i = 0; i < 90; i++ ) // 画50个刻度,即共10个大格,每个小格中画5个刻度
{
var stop = start + 0.015 * Math.PI ;

context.beginPath();

context.arc( point.x, point.y, radius, start, stop - 0.003 * Math.PI, false);

context.stroke();

context.closePath();
start = stop;

if (i == 29)
{
context.setStrokeStyle('rgba(255, 128, 0, 1)')
}
else if (i == 69)
{
context.setStrokeStyle('#C23531')
}
}


{ //画指针
//var value1 = 77; //表盘当前值
var radius = 115;
var x = Math.floor(radius * Math.cos((-1.5 * Math.PI + value1/2 * 1.5 * Math.PI / 100))) + point.x;
var y = Math.floor(radius * Math.sin((-1.5 * Math.PI + value1/2 * 1.5 * Math.PI / 100))) + point.y;

context.beginPath();

//context.setFillStyle('rgba(255, 0, 123, 0.3)');
context.setFillStyle('rgba(20, 50, 120, 1)');
context.moveTo(x, y)

radius = 15;
x = Math.floor(radius * Math.cos((-1 * Math.PI + value1/2 * 1.5 * Math.PI / 100))) + point.x;
y = Math.floor(radius * Math.sin((-1 * Math.PI + value1/2 * 1.5 * Math.PI / 100))) + point.y;
context.lineTo(x, y);

radius = 20;
x = Math.floor(radius * Math.cos((-0.5 * Math.PI + value1/2 * 1.5 * Math.PI / 100))) + point.x;
y = Math.floor(radius * Math.sin((-0.5 * Math.PI + value1/2 * 1.5 * Math.PI / 100))) + point.y;
context.lineTo(x, y);

radius = 15;
x = Math.floor(radius * Math.cos((0 * Math.PI + value1/2 * 1.5 * Math.PI / 100))) + point.x;
y = Math.floor(radius * Math.sin((0 * Math.PI + value1/2 * 1.5 * Math.PI / 100))) + point.y;
context.lineTo(x, y);

context.fill();

context.setTextAlign('center')
context.fillText(value1.toString(), 200, 250)

context.closePath();
}



//context.draw();


}


//========================================= small meter =====================================================

IncMeter2();



//var context = pm.createCanvasContext('Canvas1', this) //获取画布对象
if (context)
{


var point = { x: 350, y: 330 }; //圆心坐标,相对于画布
var radius = 75; //半径
var start = -0.8 * Math.PI; //起始弧度

context.setLineWidth(30)
context.setStrokeStyle('#91C7AE')
context.setFillStyle('#91C7AE');

for( var i = 0; i <= 4; i++ )
{
var stop = start + 0.15 * Math.PI ; //结束弧度
var x = Math.floor(108 * Math.cos(start)) + point.x;
var y = Math.floor(108 * Math.sin(start)) + point.y;
var v = 25 * i;


if (i >= 2)
context.fillText(v.toString(), x-10 , y);
else
context.fillText(v.toString(), x, y);

if (i == 4)
break;

switch(i){
case 0: context.setStrokeStyle('#ff0000'); break;
case 1: context.setStrokeStyle('#ff7f00'); break;
case 2: context.setStrokeStyle('#91C7AE'); break;
case 3: context.setStrokeStyle('#00ff00'); break;
default: break;
}


context.beginPath(); //开始新的路径

context.arc( point.x, point.y, radius, start, stop - 0.006 * Math.PI, false); //画一段圆弧

context.stroke(); //填充路径

context.closePath(); //关闭路径
start = stop;

if (i == 1)
{
context.setStrokeStyle('#63869E')
context.setFillStyle('#63869E');
}
else if (i == 7)
{
context.setStrokeStyle('#C23531')
context.setFillStyle('#C23531');
}
}

//----------------------------------------------------//
//画背光弧
context.beginPath() //开始路径
context.setLineWidth(10)
if( lightFlag>0 ) context.setStrokeStyle( 'rgba(255, 0, 0, 1)');
else context.setStrokeStyle( 'rgba(0, 0, 0, 1)');
context.arc( point.x, point.y, 120, -0.8 * Math.PI, -0.2 * Math.PI, false);
context.stroke()
context.closePath();
//----------------------------------------------------

{ //画指针
//var value = value2; //表盘当前值
var radius = 65;
var x = Math.floor(radius * Math.cos((-0.8 * Math.PI + value2/2.5 * 1.5 * Math.PI / 100))) + point.x;
var y = Math.floor(radius * Math.sin((-0.8 * Math.PI + value2/2.5 * 1.5 * Math.PI / 100))) + point.y;

context.beginPath();

//context.setFillStyle('rgba(0, 0, 255, 0.7)');
context.setFillStyle('rgba(20, 50, 120, 1)');

context.moveTo(x, y)

radius = 8;
x = Math.floor(radius * Math.cos((-0.3 * Math.PI + value2/2.5 * 1.5 * Math.PI / 100))) + point.x;
y = Math.floor(radius * Math.sin((-0.3 * Math.PI + value2/2.5 * 1.5 * Math.PI / 100))) + point.y;
context.lineTo(x, y);

radius = 10;
x = Math.floor(radius * Math.cos((0.20 * Math.PI + value2/2.5 * 1.5 * Math.PI / 100))) + point.x;
y = Math.floor(radius * Math.sin((0.20 * Math.PI + value2/2.5 * 1.5 * Math.PI / 100))) + point.y;
context.lineTo(x, y);

radius = 8;
x = Math.floor(radius * Math.cos((0.65 * Math.PI + value2/2.5 * 1.5 * Math.PI / 100))) + point.x;
y = Math.floor(radius * Math.sin((0.65 * Math.PI + value2/2.5 * 1.5 * Math.PI / 100))) + point.y;
context.lineTo(x, y);

context.fill();

context.setTextAlign('center')
//context.fillText(value.toString(), 200, 250)
context.fillText(value2.toString(), point.x, 345)

context.closePath();
}



//context.draw();
}


context.draw();

//=================================================== end ========================================================//
},


经验证,功能正常,至此,目标达成。


下篇------完善平板电脑UI系统功能




一 目标:
1 将仪表APP加入系统中,面板切换时具有“滑入”效果; 2 加入滑动解锁功能;
二、方法:
1 滑动解锁,通过判断Slider控件的值判断滑动的位置,当满足预定要求时触发跳转函数实现解锁; 2 本次采用新建页面,设置页面“移动”属性,照搬代码的方式实现APP移植。
三、步骤:
1 打开“PhotoBrowser”工程,新建页面------page3,按照“上篇------制作仪表盘APP”的方法添加空间并设置对应属性(注意,先前为横屏,现在改为竖屏),如下图所示(特别注意:页面属性的设置中添加了“移动”选择):
11.png
2 将上篇已经编辑好的代码复制到page3.js中
3 在page1中添加一个按钮控件---仪表盘,设置其属性并将事件驱动方法编写如下:
onButton2 : function(e) { console.dir(e); pm.navigateTo({url:"page3/page3"}); },
4 运行程序,触摸“仪表盘”按钮即可跳转到“仪表盘”页面,如下图所示:
14.png
12.png
5 调整仪表的坐标,使其适配页面。
6 并编写“返回”按键的驱动方法,代码如下:
onButtonE : function(e) { console.dir(e); pm.navigateBack(); },
7 运行程序效果如下
此为静态图,稍后再贴GIF动图
13.png
至此,仪表APP加入成功,并成功实现了“滑动”“登台”的表演。下面将为滑动解锁内容。 PS: 突然发现如果要增加滑动解锁功能需要增加一个页面,且页面的顺序要做“大规模调整”,有没有简便快捷的方法,我目前还未想好,也就暂且打住,留在下次发帖时再作补充吧。
























下载附件[Photo_Meter.rar]

查看更多

关注者
0
被浏览
2.4k
1 个回答
bernard
bernard 2018-09-18
中间的渐变圆是点睛之笔啊

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友