flythings优化环形滑条滑动效果

适用场景说明

此代码针对环形滑动条末端滑动不灵敏情况做优化。使用此代码如果对控件注册监听,会导致没有stop事件,请悉知。

源代码

将此份代码命名为circleBar.h,然后#include到对应界面。

/*
 * circleBar.h
 *
 *  Created on: 2024年1月31日
 *      Author: Z20、Z21 86面板FAE
 */

#ifndef LOGICSELF_CIRCLEBAR_H_
#define LOGICSELF_CIRCLEBAR_H_

#include <math.h>

//Π,计算角度使用
#define PI 3.14159265
//点击到左右边缘的可触摸偏移值(比如起始角度-135度,现在偏移10度那么你点-140度位置也能触发)
#define TOUCH_OFFSET 10 //单位:度

namespace
{

/*
 * @brife 获取中心坐标
 * @param circleBar 环形滑条指针
 * @return ctrlPos控件中心坐标
 * */
static const MotionEvent getCtrlCenterPos(const ZKCircleBar* circleBar)
{
	const int left = circleBar->getPosition().mLeft;
	const int top = circleBar->getPosition().mTop;
	const int width = circleBar->getPosition().mWidth;
	const int height = circleBar->getPosition().mHeight;

	//中心坐标
	MotionEvent center;
	center.mX = left + width/2;
	center.mY = top + height/2;

	return center;
}

/*
 * @brife 计算X、Y的偏移
 * @param center 中心位置
 * @param ev 触摸事件
 * @return 返回X、Y偏移
 * */
static const MotionEvent calculateCoordinateOffset(const MotionEvent& center, const MotionEvent& ev)
{
	const int xOffset = ev.mX - center.mX;
	const int yOffset = ev.mY - center.mY;

	MotionEvent offset;
	offset.mX = xOffset;
	offset.mY = yOffset;

	return offset;
}

/*
 * @brife 计算角度
 * @param xOffset x位置偏移
 * @param yOffset y位置偏移
 * @return 返回角度
 * */
static const double calculateAngle(const int& xOffset, const int& yOffset)
{
	//判断是否在坐标轴上
	if(0 == xOffset && 0 < yOffset) //Y正半轴
	{
		return 0;
	}
	else if(0 > xOffset && 0 == yOffset) //X负半轴
	{
		return -90;
	}
	else if(0 == xOffset && 0 < yOffset) //Y负半轴
	{
		return -180;
	}
	else if(0 < xOffset && 0 == yOffset) //X正半轴
	{
		return 90;
	}

	//第二象限
	if(0 > xOffset && 0 > yOffset)
	{
		const double scale = 1.0*xOffset/yOffset;
		const double angle = atan(scale) * 180 / PI;
//		LOGD("--%d-- --%s-- angle:%.2lf scale:%.2lf xOffset:%d yOffset:%d\n", __LINE__, __FILE__, angle, scale, xOffset, yOffset);
		return -angle;//加负号,将角度变为负值
	}
	//第三象限
	else if(0 > xOffset && 0 < yOffset)
	{
		const double scale = 1.0*yOffset/xOffset;
		const double angle = -90+/*角度值是负的,所以是加*/atan(scale) * 180 / PI;
		return angle;
	}
	//第一象限
	if(0 < xOffset && 0 > yOffset)
	{
		const double scale = 1.0*xOffset/yOffset;
		const double angle = atan(scale) * 180 / PI;
		return -angle; //加负号,将角度变为正值
	}
	//第四象限
	else if(0 < xOffset && 0 < yOffset)
	{
		const double scale = 1.0*yOffset/xOffset;
		const double angle = 90+atan(scale) * 180 / PI;
//		LOGD("--%d-- --%s-- angle:%.2lf scale:%.2lf xOffset:%d yOffset:%d\n", __LINE__, __FILE__, angle, scale, xOffset, yOffset);
		return angle;
	}
	else
	{
		LOGD("--%d-- --%s-- xOffset:%d yOffset:%d 计算出错!!!\n", __LINE__, __FILE__, xOffset, yOffset);
	}

	return 0.0;
}

/*
 * @brife 是否点击到环形滑条
 * @param circleBar 环形滑条指针
 * @param ev 触摸事件
 * @param touchRadius 触摸半径(点在控件上且在这半径之外的位置,才算点到控件)
 * @param minAngle 最小角度
 * @param maxAngle 最大角度
 * @return true 触摸到控件;false 未触摸到控件
 * */
static const bool wetherTouchCtrl(ZKCircleBar* circleBar, const MotionEvent& ev,
		const int& touchRadius, const double& minAngle, const double& maxAngle)
{
	static bool isTourched = false;
    switch (ev.mActionStatus) {
    	//触摸按下判断是否点击到控件
		case MotionEvent::E_ACTION_DOWN:
			//控件不可见或没点击到控件返回false
			if(false == circleBar->isVisible() || false == circleBar->getPosition().isHit(ev.mX, ev.mY))
			{
				isTourched = false;
				return isTourched;
			}
			break;
		default:
			return isTourched;
			break;
	}
    //设置控件触摸穿透
    circleBar->setTouchPass(true);
    //获取控件中心点
    const MotionEvent center = getCtrlCenterPos(circleBar);
    //中心点距离触摸点的距离
    const MotionEvent offset = calculateCoordinateOffset(center, ev);
    //判断点击位置是否为可滑动范围
    const double angle = calculateAngle(offset.mX, offset.mY);
    if(minAngle-TOUCH_OFFSET > angle || maxAngle+TOUCH_OFFSET < angle)
    {
		isTourched = false;
		return isTourched;
    }
    //返回触摸点是否在触摸半径之外
    isTourched = (touchRadius*touchRadius < (offset.mX*offset.mX + offset.mY*offset.mY));

	return isTourched;
}

/*
 * @brife 根据坐标设置环形滑动条进度值
 * @param circleBar 环形滑条指针
 * @param ev 触摸事件
 * @param minAngle 最小角度
 * @param maxAngle 最大角度
 * @param touchRadius 触摸半径(默认值是0)
 * */
static void setCircleBarProgress(ZKCircleBar* circleBar, const MotionEvent& ev,
		const double& minAngle, const double& maxAngle, const int& touchRadius = 0)
{
	//点击时为触摸到控件函数返回
	if(false == wetherTouchCtrl(circleBar, ev, touchRadius, minAngle, maxAngle)){return;}

    //获取控件中心点
    const MotionEvent center = getCtrlCenterPos(circleBar);
    //中心点距离触摸点的距离
    const MotionEvent offset = calculateCoordinateOffset(center, ev);
	//计算角度
	double angle = calculateAngle(offset.mX, offset.mY);
//	LOGD("--%d-- --%s-- center x:%d center y:%d offset x:%d offset y:%d angle:%.2lf\n", __LINE__, __FILE__,
//			center.mX, center.mY, offset.mX, offset.mY, angle);
	//限定角度范围
	angle = (minAngle > angle)? minAngle:(maxAngle < angle)? maxAngle:angle;
	//可滑动角度范围
	const double totalAngle = maxAngle-minAngle;
	//将角度转换为正值
	angle += totalAngle/2;
	//进度值
	const int progress = angle/totalAngle*circleBar->getMax();
//	LOGD("--%d-- --%s-- angle:%.2lf totalAngle:%.2lf progress:%d\n", __LINE__, __FILE__, angle, totalAngle, progress);
	//设置进度值
	circleBar->setProgress(progress);
}
}
#endif /* LOGICSELF_CIRCLEBAR_H_ */

使用说明

在界面对应的触摸回调函数直接调用即可,如下:

/**
 * 有新的触摸事件时触发
 * 参数:ev
 *         新的触摸事件
 * 返回值:true
 *            表示该触摸事件在此被拦截,系统不再将此触摸事件传递到控件上
 *         false
 *            触摸事件将继续传递到控件上
 */
static bool onXXXActivityTouchEvent(const MotionEvent &ev) {
    //设置环形滑条滑动
    setCircleBarProgress(circleBar, ev, -135.0, 135.0);
	return false;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值