UGUI滑动条最小值控制

有时我们要实现一些比较特殊的滑动条效果,如下所示:

请添加图片描述
就是Slider去掉了Handle,然后Fill在最低的时候要限制在某个范围以上。颜色的变化忽略。

这样的实现目前我知道的总共有两种

  • 更改UI的布局格式
  • 写个脚本限制最低范围并重新映射范围,这种需要将滑动值的监听放在该脚本上

我自己实现的是第二种,先一个个看下

更改UI的布局格式

在这里插入图片描述
在这里插入图片描述
Slider控制的是Fill这个物体的Anchor的区域是否完全覆盖FillArea,所以当在Slider的value为0的时候,把anchor调节成如图所示,后面调节slider,当Value为0时,就不会fill完全消失了。这样做的话,在value为1的时候,图中的圆圈的上半部分是超出FillArea的。

这个的原理是,
在value不为0时,fill的RectTransform信息是这样的

在这里插入图片描述
Top代表了anchor所围成的矩形的顶部与这个UI物体本身的面积矩形的顶部的差值,是不会变的,其他的Left Right都是一样的。
而在保持这种不变的情况下,调节Anchors的区域就变相调节了Fill的大小,但是不管怎样这个距离的差值都在的。
在这里插入图片描述

但是在value为0的时候,fill的recttransform的信息是

在这里插入图片描述
但因为slider调节的是anchor的区域,所以这时的RectTransform情况并不用于参考,参考的还是上上图的情况。

重新映射范围

简单来说是,在检测到slider的value达到最低值时,限制为最低值然后将限制的最低值和1之间的区域映射为0-1的区域,并传给代理。缺点是原本对slider的值监听需要改为对此脚本的值监听。

按照映射的需求,在限定最低值时认为是0,在限定最高值是认为是1,这中间是线性变化的过程。那么现在是将最低值到1的这个过程看成是0-1的变化范围了。

所以原理是,将代码中限制的最低值比如0.15到默认最高值1之间的范围映射到(0-1),那么滑动条在这里面的值x就要以这个最低值为零点,先算出相对的偏移(x - 0.15),然后这个偏移值从(1 - 0.15)的范围映射到(1-0)的范围,即乘以
(1 - 0) / (1 - 0.15)这个比值。

乘以

public class SettingsSlideMinControl : MonoBehaviour
{
    
    
    [SerializeField]
    private Slider _slider;
    
    [SerializeField, Range(0,1)]
    private float minValue;


    private UnityAction<float> onReachMin;
    private UnityAction<float> onOutofMin;
    
    private UnityAction<float> onDealedSlide;


    private void Awake()
    {
    
    
    }

    // Start is called before the first frame update
    void Start()
    {
    
    
        _slider.onValueChanged.AddListener(OnSlide);
    }
    
     void OnReachMin(float value)
     {
    
    
         onReachMin?.Invoke(value);
     }
     
     void OnOutOfMin(float value)
     {
    
    
         onOutofMin?.Invoke(value);
     }
     
     
     public void SetOnReachMin(UnityAction<float> onReachMin)
     {
    
    
         this.onReachMin += onReachMin;
     }
     
     public void RemoveOnReachMin(UnityAction<float> onReachMin)
     {
    
    
         this.onReachMin -= onReachMin;
     }
     
     public void SetOnOutOfMin(UnityAction<float> onOutofMin)
     {
    
    
         this.onOutofMin += onOutofMin;
     }
     
     public void RemoveOnOutOfMin(UnityAction<float> onOutofMin)
     {
    
    
         this.onOutofMin -= onOutofMin;
     }
     
     public void AddOnSlideListener(UnityAction<float> onDealedSlide)
     {
    
    
         this.onDealedSlide += onDealedSlide;
     }
     
     public void RemoveOnSlide(UnityAction<float> onDealedSlide)
     {
    
    
         this.onDealedSlide -= onDealedSlide;
     }


     public void SetSlideValueWithoutNotify(float value)
     {
    
    
         float mappedValue = ValueMap(value);
        _slider.SetValueWithoutNotify(mappedValue);   
     }

     /// <summary>
     /// 将0-1的值映射到缩短后的值
     /// </summary>
     /// <param name="originValue"></param>
     /// <returns></returns>
     public float ValueMap(float originValue)
     {
    
    
         float mappedValue = minValue + originValue * (1 - minValue) / (1 - 0);

         return mappedValue;
     }
     
     /// <summary>
     /// 将缩短后的值映射为0-1的值
     /// </summary>
     /// <param name="originValue"></param>
     /// <returns></returns>
     public float ValueReversemap(float originValue)
     {
    
    
         float mappedValue =  (originValue - minValue)  * (1 - 0) / (1 - minValue) ;
         
         return mappedValue;
     }
 

     private bool isCurrentReachMin;
    // Update is called once per frame
    void OnSlide(float value)
    {
    
    
        if (value < minValue)
        {
    
    
            // _slider.SetValueWithoutNotify(minValue);
            _slider.value = minValue;
            OnReachMin(minValue);
            isCurrentReachMin = true;
            onDealedSlide(0);
            // print(" dealedValue " + 0);

        }
        else
        {
    
    
            if (isCurrentReachMin)
            {
    
    
                isCurrentReachMin = false;
                OnOutOfMin(value);
            }
            
            //这里因为是将调整范围后的slider的值映射为0-1范围,所以用ValueReversemap
            float dealedValue = ValueReversemap(value);
            // print(" dealedValue " + dealedValue);

            onDealedSlide?.Invoke(dealedValue);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43149049/article/details/122936212