【仿汽车之家】价格区间选择控件

本文介绍如何在iOS应用中实现一个类似汽车之家的价目区间选择器,包括界面搭建、手势响应、数值显示更新及优化等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

仿照汽车之家iOS客户端“找车”栏目的价格区间选择控件,最终实现效果如下:






一、界面实现

*根据屏幕大小以及刻度的大小,宏定义需要用到的一些值

#define SCREENW [UIScreen mainScreen].bounds.size.width
#define SCREENH [UIScreen mainScreen].bounds.size.height
#define PRICEBGW  271.0
#define PRICEBGH  21.0
#define PRICEBGX (SCREENW - PRICEBGW)*0.5
#define PRICEBGY (SCREENH - PRICEBGH)*0.5
#define PRICEMAX (SCREENW*0.5 + PRICEBGW*0.44)
#define PRICEMIN (SCREENW*0.5 - PRICEBGW*0.45)
#define NODE1  (PRICEBGX + 103)


项目中用了两张图片,一张是刻度图(紫色框中的UIIMageView,图片命名为priceRuler@2x.png),一张是把手图(两个红色框内分别有一个UIIMageView,图片命名为xiabashou@2x.png),蓝色框内的进度条,使用一个UIView来实现,而使用UILabel来显示用户选择的数值范围。



priceRuler@2x.png



xiabashou@2x.png



我们把界面实现的代码写到一个函数中,函数名为setUpView,并在viewDidLoad中调用。

-(void)setUpView{
    //数值显示
    resultLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 100, SCREENW, 60)];
    [resultLabel setTextAlignment:NSTextAlignmentCenter];
    [resultLabel setFont:[UIFont systemFontOfSize:18]];
    [self.view addSubview:resultLabel];
    
    //刻度图
    UIImageView *priceBg = [[UIImageView alloc] initWithFrame:CGRectMake(PRICEBGX, PRICEBGY, PRICEBGW, PRICEBGH)];
    [priceBg setImage:[UIImage imageNamed:@"priceBg"]];
    [self.view addSubview:priceBg];
    
    //蓝色进度条
    progressView = [[UIView alloc] initWithFrame:CGRectMake(PRICEBGX, CGRectGetMaxY(priceBg.frame)-2, PRICEBGW, 2.f)];
    [progressView setBackgroundColor:[UIColor colorWithRed:30.0/255.0 green:144.0/255.0 blue:255.0/255.0 alpha:1.0]];
    [self.view addSubview:progressView];
    
    //左把手
    CGFloat commonHandImageViewW = 20.f;
    CGFloat commonHandImageViewH = 25.f;
    CGFloat leftHandImageViewX = PRICEBGX - commonHandImageViewW*0.5;
    CGFloat leftHandImageViewY = PRICEBGY + commonHandImageViewH;
    leftHandImageView = [[UIImageView alloc] initWithFrame:CGRectMake(leftHandImageViewX, leftHandImageViewY, commonHandImageViewW, commonHandImageViewH)];
    [leftHandImageView setImage:[UIImage imageNamed:@"xiabashou"]];
    [self.view addSubview:leftHandImageView];
    
    //右把手
    CGFloat rightHandImageViewX = CGRectGetMaxX(priceBg.frame) - commonHandImageViewW*0.5;
    CGFloat rightHandImageViewY = leftHandImageViewY;
    rightHandImageView = [[UIImageView alloc] initWithFrame:CGRectMake(rightHandImageViewX, rightHandImageViewY, commonHandImageViewW, commonHandImageViewH)];
    [rightHandImageView setImage:[UIImage imageNamed:@"xiabashou"]];
    [self.view addSubview:rightHandImageView];

}

现在运行项目,已经可以看到一个区间选择器了,但是我们在屏幕进行任意拖动操作,界面并没有任何改变。因此我们需要使得app能够响应我们的手势。



二、响应用户手势

为了响应用户的拖动手势,给两个把手(UIIMageView)分别添加滑动手势识别(UIPanGestureRecognizer)。我们在setUpView中继续添加如下代码


-(void)setUpView{
   
    ….….
   
    //给左把手添加滑动手势识别
    UIPanGestureRecognizer *leftPanRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(leftHandMove:)];
    [leftPanRecognizer setMinimumNumberOfTouches:1];
    [leftPanRecognizer setMaximumNumberOfTouches:1];
    [leftHandImageView setUserInteractionEnabled:YES];
    [leftHandImageView addGestureRecognizer:leftPanRecognizer];
    
    //给右把手添加滑动手势识别
    UIPanGestureRecognizer *rightPanRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(rightHandMove:)];
    [rightHandImageView setUserInteractionEnabled:YES];
    [rightHandImageView addGestureRecognizer:rightPanRecognizer];
    
}

实现leftHandMove:和rightHandMove:方法,处理滑动事件:


-(void)leftHandMove:(UIPanGestureRecognizer *)pan{
    CGPoint point = [pan translationInView:leftHandImageView];
    CGFloat x = leftHandImageView.center.x + point.x;
    if(x > PRICEMAX){
        x = PRICEMAX;
    }else if (x< PRICEBGX ){
        x = PRICEBGX;
    }
    
   leftHandImageView.center = CGPointMake(ceilf(x), leftHandImageView.center.y);
   
    [pan setTranslation:CGPointZero inView:self.view];
}

-(void)rightHandMove:(UIPanGestureRecognizer *)pan{
    CGPoint point = [pan translationInView:rightHandImageView];
    CGFloat x = rightHandImageView.center.x + point.x;

    if(x>PRICEBGX+PRICEBGW){
        x = PRICEBGX+PRICEBGW;
    }else if (x<PRICEMIN){
        x = PRICEMIN;
    }
    
   rightHandImageView.center = CGPointMake(ceilf(x), rightHandImageView.center.y);
    
 }

在leftHandMove:方法中,我们使用translationInView函数,得到在指定的View坐标系中的改变值point,将原来的x坐标值加上改变的值后,若超出符合要求的刻度范围,我们要设置其为边界值,然后再更新把手的位置,否则直接更新即可。rightHandMove:同理实现。

尝试运行项目并拖动把手,现在把手的位置可以水平拖动了,但是UILabel还没有显示我们选中的范围,蓝色进度条也没随之改变。


三、更新数值显示和蓝色进度条

为了得到上一步中用户选中的值,我们先声明两个个全局变量:

float leftValue;
float rightValue;
在viewDidLoad中初始化
- (void)viewDidLoad {
    [super viewDidLoad];
    leftValue = 0;
    rightValue = 100;
    [self setUpView];
}
然后在leftHandMove:和rightHandMove:中将用户选中的值分别赋值给leftValue和rightValue。
<pre code_snippet_id="1582410" snippet_file_name="blog_20160219_8_6433823" name="code" class="objc">-(void)leftHandMove:(UIPanGestureRecognizer *)pan{

……

leftValue =  x;
</pre><pre code_snippet_id="1582410" snippet_file_name="blog_20160219_9_4132529" name="code" class="objc">}
 
     

现在,我们写一个更新数值和进度条的函数,函数名为updateData。

-(void)updateData{
    [resultLabel setText:[NSString stringWithFormat:@"%.0f~%.0f",leftValue,rightValue]];

}

我们再一次运行程序,滑动手柄,数值虽然改变了,但并不是我们想要的价格数值!!



这是因为屏幕的坐标和刻度图的坐标范围并不一致,因此我们需要将数据处理一下。可能你已经发现,刻度图中的范围并不是均匀分布的,而是分成三段:0~25、25~40、40~100。因此我们在处理时需要分段处理。

我们写一个将左边转换为价格的转换函数:

//坐标->价格
-(CGFloat)x2price:(CGFloat)x{
    
    CGFloat price = 0.f;
    
    //<5
    if(x < PRICEMIN){
        price = 0;
    }
    //5~25
    else if (x < PRICEBGX + 133){
        price = (x - PRICEMIN) / 120 * 20 + 5;
    }
    //25~40
    else if (x < PRICEBGX +  163){
        price = (x - PRICEBGX - 133) *0.5 + 25;
    }
    //40~100
    else if (x < PRICEBGX + 253){
        price = (x - PRICEBGX - 163) * 2 / 3 + 40;
    }
    //100+
    else{
        price = 100;
    }
    
    return price;
}

将leftHandMove:中的leftValue =  x;修改为如下

-(void)leftHandMove:(UIPanGestureRecognizer *)pan{
 
    ……

    leftValue = [self x2price:ceilf(x)];
}

同理rightHandMove:也做相应处理。重新运行程序,滑动把手,显示的价格数值正是我们所期望的。

我们还要更新蓝色进度条,只需修改它的frame即可:


-(void)updateData{
    [resultLabel setText:[NSString stringWithFormat:@"%.0f~%.0f",leftValue,rightValue]];

    CGRect progressRect = CGRectMake(leftHandImageView.center.x, progressView.frame.origin.y, rightHandImageView.center.x - leftHandImageView.center.x, progressView.frame.size.height);
    progressView.frame = progressRect;
}

四、优化

当将右边的把手一直往左滑动,它将滑到左边把手的左边,也就是用户选择的区间中,上界值比下界值更小了!这并不是我们期望的结果。我们希望上界至少要比下界大1个单位,所以当用户滑动右把手到上界比下界小于等于1时,左把手也要跟着滑动,与右把手始终保持1个单位。

我们在rightHandMove:函数中添加如下代码:

-(void)rightHandMove:(UIPanGestureRecognizer *)pan{
      
    ……

    if (rightValue-leftValue <= 1) {
        leftValue = rightValue - 1;
        leftHandImageView.center = CGPointMake([self price2x:leftValue], leftHandImageView.center.y);
    }

}

同理在leftHandMove:函数中添加对应代码:

-(void)leftHandMove:(UIPanGestureRecognizer *)pan{
    
   ……

   if (rightValue-leftValue <= 1) {
        rightValue = leftValue + 1;
        rightHandImageView.center = CGPointMake([self price2x:rightValue], rightHandImageView.center.y);
    }
    
}

注意到函数中用到了方法price2x:,这个函数是将价格转换为对应的x坐标,作用于前面用到的x2price:刚好相反。

//价格->坐标
-(CGFloat)price2x:(CGFloat)price{
    
    CGFloat x;
    //<5
    if (price<5) {
        x = PRICEBGX;
    }
    //5~25
    else if (price >= 5 && price < 25) {
        x = (price-5) * 6 + PRICEMIN;
    }
    //25~40
    else if (price >= 25 && price <40) {
        x = (price-25) * 2 + 133 + PRICEBGX;
    }
    //40~100
    else if (price >=40 && price <100){
        x = (price-40) * 3/2 +163 + PRICEBGX;
    }else if(price >= 100){
        x = PRICEBGX + PRICEBGW;
    }
    
    return x;
}

运行程序,现在已经不能将右把手拖动到左把手的前面的吧~

完整源代码下载:http://download.youkuaiyun.com/detail/dolacmeng/9436673





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值