依赖坐标范围计算设置间隔数量,可是用控件达成此效率时上边包车型地铁坐标密密层层的

图片 8

Teechart控件求助写了一个实时显示数据的曲线程序,需要在曲线上加上XY轴坐标,但是用控件实现此功能时下面的坐标密密麻麻的,想只要三根最好峰的坐标其他不现实,有没有什么好办法?

闭合命令:

纵坐标刻度带有小数,观察数据曲线时,就不容易计算曲线的波动。解决方法很简单,就是设置曲线坐标范围后,根据坐标范围计算设置间隔数量,让每个刻度都是整数,例如:

原创文章,转载请注明出处,🙏

图片 1

还可以使用Mini-Language为Data属性赋值,Mini-Language强大。

这样就解决了初始化时曲线控件的坐标轴间隔取整问题,但是曲线控件显示过程中认为进行缩放,坐标轴间隔就会随着人画的缩放区域变化,出现小数。

效果分析

图片 2两个三阶贝塞尔曲线

1、默认状态:直线,首尾标注,默认值标注。2、手指按下:曲线动画执行,标识小圆规则地放大,值的标注根据曲线波峰相对位置不变,向上同速移动,同时,标注背景渐变加深,动画结束。3、手指拖动效果:曲线、小圆形、标注三者同时跟随触摸点移动,同时更新标注值。4、手指离开屏幕:曲线收回动画执行,标识小圆规则缩小到默认状态,选中的值跟随波峰下沉到默认状态,标注背景渐变消失,动画结束。

图片 3缩放效果

拆解状态三部分:默认状态、触摸过程中、触摸后状态。其中默认状态下指示器很小的圆形,距离水平曲线下方一个约定距离,当按下过程中,圆最下方坐标不变,圆直径逐渐增大,圆顶部与曲线的距离不变,直到动画结束。

二次贝赛尔曲线命令:

图片 4

功能分析

1、控件内元素:标尺、标注用的小圆、选中值,均可配置各自的颜色,2、可配置值范围,3、可配置默认值,4、可实时监听选中的值。5、可显示单位。

<Path  Width="456" Height="566" Data="M 10,40 L 300,180 V 400 H 140 S 400,240 400,800 Z" HorizontalAlignment="Left" Margin="12,20,0,0" Name="path2" Stroke="Red" StrokeThickness="3" VerticalAlignment="Top" />
1 mAyis0->setTickCount(9); //会划分成几个单位·2 mAyis0->setRange(-100,700);3 mAyis0->setLabelFormat("%d"); //设置刻度的格式

效果图

图片 5preview

  如:M
100,200

图片 6

技术分析

通过静态截图可知本控件主要元素为触摸触发的曲线和其伸缩效果。让我们来简单分析一下曲线部分的结构://这里展示曲线拆解图拆解后,触摸部分为六阶贝塞尔曲线,五个基准点,四个控制点,我们将它拆分成两个三阶曲线即可。其中,首尾基准点的Y坐标固定,X坐标随着触摸位置相对移动,剩下的基准点X坐标相对固定,Y坐标根据动画规律升降。再说控制点,为保障默认状态下,曲线部分为水平,首尾两个控制点的Y坐标固定,X坐标相对固定,中间两个控制点Y坐标和中间那个基准点一致,X相对中间基准点固定。(通过上面的拆解,可以让曲线在默认状态下是一条水平直线,并且在按下状态下,与水平位置、波峰位置,能有比较自然的过度弧形,不至于那么生硬。)

普通圆形,相对自身底部向上变大、向下缩小还原。

按下时的动画采用普通的ValueAnimator,匀速LinearInterpolator。另外还有个选中值的背景变化,根据动画进度改变画笔Alpha值即可。//这里写点动画代码啰。

泡杯茶,挽起袖子开撸!继承View:

public class BezierSeekBar extends View { public BezierSeekBar(Context context) { super; init(context, null); } public BezierSeekBar(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(context, attrs); } public BezierSeekBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public BezierSeekBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context, attrs); } private void init(Context context, AttributeSet attrs) { this.context = context; }}

先绘制出曲线效果:

 //第一个三阶曲线 bezierPath.moveTo(this.fingerX - circleRadiusMax * 2 * 3,  2 * height / 3); bezierPath.cubicTo(this.fingerX - circleRadiusMax * 2 * 2,  2 * height / 3, this.fingerX - circleRadiusMax * 2 * 1,  2 * height / 3 - bezierHeight, this.fingerX,  2 * height / 3 - bezierHeight); //第二个三阶曲线 bezierPath.moveTo(this.fingerX,  2 * height / 3 - bezierHeight); bezierPath.cubicTo(this.fingerX + circleRadiusMax * 2,  2 * height / 3 - bezierHeight, this.fingerX + circleRadiusMax * 2 * 2,  2 * height / 3, this.fingerX + circleRadiusMax * 2 * 3,  2 * height / 3);

改变其Y坐标,让曲线恢复默认状态:绘制完整线条:

 //line1 bezierPath.reset(); bezierPath.moveTo(0,  2 * height / 3); bezierPath.lineTo(this.fingerX - circleRadiusMax * 2 * 3,  2 * height / 3); //bezier1 bezierPath.moveTo(this.fingerX - circleRadiusMax * 2 * 3,  2 * height / 3); bezierPath.cubicTo(this.fingerX - circleRadiusMax * 2 * 2,  2 * height / 3, this.fingerX - circleRadiusMax * 2 * 1,  2 * height / 3 - bezierHeight, this.fingerX,  2 * height / 3 - bezierHeight); //bezier2 bezierPath.moveTo(this.fingerX,  2 * height / 3 - bezierHeight); bezierPath.cubicTo(this.fingerX + circleRadiusMax * 2,  2 * height / 3 - bezierHeight, this.fingerX + circleRadiusMax * 2 * 2,  2 * height / 3, this.fingerX + circleRadiusMax * 2 * 3,  2 * height / 3); //line2 bezierPath.lineTo(width,  2 * height / 3); canvas.drawPath(bezierPath, bezierPaint);

添加Touch事件拦截,按下时显示曲线:

 @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction { case MotionEvent.ACTION_DOWN: fingerX = event.getX(); if (fingerX < 0F) fingerX = 0F; if (fingerX > width) fingerX = width; //触摸介质进入控件,开始动画过渡 this.animatorFingerIn.start(); break; case MotionEvent.ACTION_MOVE: fingerX = event.getX(); if (fingerX < 0F) fingerX = 0F; if (fingerX > width) fingerX = width; postInvalidate(); break; case MotionEvent.ACTION_UP: //触摸介质离开控件,执行动画 this.animatorFingerOut.start(); break; } valueSelected = Integer.valueOf(decimalFormat.format(valueMin + (valueMax - valueMin) * fingerX / width)); if (selectedListener != null) { selectedListener.onSelected(valueSelected); } return true; }

添加动画效果:

 this.animatorFingerIn = ValueAnimator.ofFloat; this.animatorFingerIn.setDuration; this.animatorFingerIn.setInterpolator(new LinearInterpolator; this.animatorFingerOut = ValueAnimator.ofFloat; this.animatorFingerOut.setDuration; this.animatorFingerOut.setInterpolator(new LinearInterpolator; this.animatorFingerOut.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float progress =  animation.getAnimatedValue(); animInFinshed = (progress >= 0.15F); txtSelectedBgPaint.setAlpha (255 * (progress - 0.15F))); if (progress >= 0.95F) { textPaint.setColor(colorValueSelected); } else { textPaint.setColor(colorValue); } bezierHeight = circleRadiusMax * 1.5F * progress; circleRadius = circleRadiusMin + (circleRadiusMax - circleRadiusMin) * progress; spaceToLine = circleRadiusMin * 2 * (1F - progress); postInvalidate;

绘制圆形指示器,根据动画进度改变其大小:

 canvas.drawCircle(this.fingerX,  2 * height / 3 + spaceToLine + circleRadius, circleRadius, ballPaint);

添加其它辅助元素后,配置通用属性,抛出公共方法:

 <declare-styleable name="BezierSeekBar"> //曲线颜色 <attr name="bsBar_color_line" format="reference|color" /> //圆形指示器颜色 <attr name="bsBar_color_ball" format="reference|color" /> //阀值的文本颜色 <attr name="bsBar_color_value" format="reference|color" /> //选中值的文本颜色 <attr name="bsBar_color_value_selected" format="reference|color" /> //选中值的文本颜色背景 <attr name="bsBar_color_bg_selected" format="reference|color" /> //阀值最小 <attr name="bsBar_value_min" format="integer" /> //阀值最大 <attr name="bsBar_value_max" format="integer" /> //默认选中值 <attr name="bsBar_value_selected" format="integer" /> //单位 <attr name="bsBar_unit" format="reference|string" /> </declare-styleable>

private void initAttr(Context context, AttributeSet attrs) { if (attrs != null) { TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.BezierSeekBar); this.colorBall = attributes.getColor(R.styleable.BezierSeekBar_bsBar_color_ball, Color.BLACK); this.colorLine = attributes.getColor(R.styleable.BezierSeekBar_bsBar_color_line, Color.BLACK); this.colorValue = attributes.getColor(R.styleable.BezierSeekBar_bsBar_color_value, Color.BLACK); this.colorValueSelected = attributes.getColor(R.styleable.BezierSeekBar_bsBar_color_value_selected, Color.WHITE); this.colorBgSelected = attributes.getColor(R.styleable.BezierSeekBar_bsBar_color_bg_selected, Color.BLACK); this.valueMin = attributes.getInteger(R.styleable.BezierSeekBar_bsBar_value_min, 30); this.valueMax = attributes.getInteger(R.styleable.BezierSeekBar_bsBar_value_max, 150); this.valueSelected = attributes.getInteger(R.styleable.BezierSeekBar_bsBar_value_selected, 65); this.unit = attributes.getString(R.styleable.BezierSeekBar_bsBar_unit) + ""; attributes.recycle(); } }

最后,测试一下:

 <tech.nicesky.bezierseekbar.BezierSeekBar android: app:bsBar_color_ball="@android:color/white" app:bsBar_color_bg_selected="@android:color/white" app:bsBar_color_line="@android:color/white" app:bsBar_color_value="@android:color/white" app:bsBar_color_value_selected="#ef5350" app:bsBar_value_min="30" app:bsBar_value_max="120" app:bsBar_value_selected="65" app:bsBar_unit="kg" android:layout_width="match_parent" android:layout_height="wrap_content" />

完美 🙂 ! 附上demo APK:

图片 7demo
apk

本控件主要涉及到贝塞尔曲线的基础理解和应用、动画的基础应用、自定义控件的常规流程,重点还是熟练各种UI效果的分析拆解和思路整理。

欢迎Star,开源地址:

圆弧命令:

如图:

某设计网经常会有很多优秀漂亮的交互设计作品,有一天,偶遇这样的效果,动画流畅,交互自然,于是埋头自己解剖其中的元素,做了个开源控件,十来天有了一百来个star,觉得很受欢迎,今天专门写这潦草几笔,分享案发经过,希望对同行有所帮助。

二.Path:路径控件通过Markup Syntax来绘制一系列的线条或通过Geometries来绘制形状,这个控件是图形控件中最复杂的。

使用qt的qchart显示数据曲线,坐标轴QValueAxis可以设置刻度间隔数量,但每个刻度的数值是根据坐标的极值除以间隔数量得到的,不一定是整数,导致曲线控件的显示刻度不适合观察。

  L/l:直线的结束点

范围-100~700,共8个区域,9个刻度,所以:

  T/t:控制点、结束点

图片 8

三次贝赛尔曲线命令:

所以还需要加入坐标轴对范围变化的响应,例如,要将坐标轴的刻度值设置成10的倍数:

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图