下拉框选择效果的实现原理

导航栏与下拉框的效果

实现的效果是在导航栏中间出现下拉框选择的效果,当选择某一个时,则上面的字也相应进行修改(此实例代码可以看Coding.net的源代码),这边有把它单独提取出来进行测试,源代码下载;接下来将简单介绍一下此实现的方式及主要代码;

1:因为我们是跟导航栏进行结合,所以这边用到的NavigationController,我们把这个页面的效果放在viewController中,弹出来的下拉列表这边是以表格的形式存在,每个则是表格的一行,行里面包括图标跟文字;

首先看一下AppDelegate.m的代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    ViewController *loginVC = [[ViewController alloc] init];
    [self.window setRootViewController:[[UINavigationController alloc] initWithRootViewController:loginVC]];
    [self.window makeKeyAndVisible];
    return YES;
}

接着是ViewController.h及ViewController.m的代码:

#import <UIKit/UIKit.h>
#import "UIViewController+DownMenu.h"

@interface ViewController : UIViewController


@end
#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, assign) NSInteger curIndex;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    _curIndex = 0;
    [self customDownMenuWithTitles:@[[DownMenuTitle title:@"冒泡广场" image:@"nav_tweet_all" badge:nil],
                                     [DownMenuTitle title:@"好友圈" image:@"nav_tweet_friend" badge:nil],
                                     [DownMenuTitle title:@"热门冒泡" image:@"nav_tweet_hot" badge:nil],
                                     [DownMenuTitle title:@"我的冒泡" image:@"nav_tweet_mine" badge:nil]]
                   andDefaultIndex:_curIndex
                          andBlock:^(id titleObj, NSInteger index) {
                              [(DownMenuTitle *)titleObj setBadgeValue:nil];
                              _curIndex = index;
                              [self refreshFirst];
                          }];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)refreshFirst
{
    NSLog(@"%ld",_curIndex);
}

@end

这边把一些内容封装到的UIViewController+DownMenu.h这个文件及实现里;

2:UIViewController+DownMenu主要代码如下:

#import <UIKit/UIKit.h>
#import "UIDownMenuButton.h"
@class DownMenuTitle;

@interface UIViewController (DownMenu)
- (UIDownMenuButton *)customDownMenuWithTitles:(NSArray *)titleList andDefaultIndex:(NSInteger)index andBlock:(void (^)(id titleObj, NSInteger index))block;
- (UIDownMenuButton *)downMenuBtn;
@end
#import "UIViewController+DownMenu.h"

@implementation UIViewController (DownMenu)
- (UIDownMenuButton *)customDownMenuWithTitles:(NSArray *)titleList andDefaultIndex:(NSInteger)index andBlock:(void (^)(id titleObj, NSInteger index))block{
    UIDownMenuButton *navBtn = [[UIDownMenuButton alloc] initWithTitles:titleList andDefaultIndex:index andVC:self];
    navBtn.menuIndexChanged = block;
    self.navigationItem.titleView = navBtn;
    return navBtn;
}
- (UIDownMenuButton *)downMenuBtn{
    if (self.navigationItem.titleView || [self.navigationItem.titleView isKindOfClass:[UIDownMenuButton class]]) {
        UIDownMenuButton *navBtn = (UIDownMenuButton *)self.navigationItem.titleView;
        return navBtn;
    }else{
        return nil;
    }
}
@end

注意:UIDownMenuButton这个就是上面每个行的封装,这边可以看到在其对它进行增加到nav里面;

3:UIDownMenuButton主要代码如下:

#import <UIKit/UIKit.h>
#import "NSString+Common.h"

@class DownMenuTitle;

@interface UIDownMenuButton : UIButton <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, assign) NSInteger curIndex;

- (UIDownMenuButton *)initWithTitles:(NSArray *)titleList andDefaultIndex:(NSInteger)index andVC:(UIViewController *)viewcontroller;
@property (nonatomic,copy) void(^menuIndexChanged)(id titleObj, NSInteger index);

@end

@interface DownMenuTitle : NSObject
@property (nonatomic, strong) NSString *titleValue, *imageName, *badgeValue;
+ (DownMenuTitle *)title:(NSString *)title image:(NSString *)image badge:(NSString *)badge;
@end
#define kNavImageWidth (15.0+5.0)
#define kDownMenu_ContentLeftPading 27.0
#define kDownMenuCellHeight 50.0
#define  kNavTitleFontSize 19
#define kScreen_Bounds [UIScreen mainScreen].bounds
#define kScreen_Height [UIScreen mainScreen].bounds.size.height
#define kScreen_Width [UIScreen mainScreen].bounds.size.width
#define kKeyWindow [UIApplication sharedApplication].keyWindow

#define DEGREES_TO_RADIANS(angle) ((angle)/180.0 *M_PI)
#define RADIANS_TO_DEGREES(radians) ((radians)*(180.0/M_PI))

#import "UIDownMenuButton.h"
#import "DownMenuCell.h"

@interface UIDownMenuButton()

@property (nonatomic, strong) NSArray *titleList;
@property (nonatomic, assign) BOOL isShowing;
@property (nonatomic, strong) UIView *mySuperView, *myTapBackgroundView;
@property (nonatomic, strong) UITableView *myTableView;

@end


@implementation UIDownMenuButton

- (UIDownMenuButton *)initWithTitles:(NSArray *)titleList andDefaultIndex:(NSInteger)index andVC:(UIViewController *)viewcontroller{
    self = [super init];
    if (self) {
        _titleList = titleList;
        _curIndex = index;
        _isShowing = NO;
        _mySuperView = viewcontroller.view;
       
        self.backgroundColor = [UIColor clearColor];
        [self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [self setTitleColor:[UIColor blackColor] forState:UIControlStateHighlighted];
        [self.titleLabel setFont:[UIFont systemFontOfSize:kNavTitleFontSize]];
        [self.titleLabel setMinimumScaleFactor:0.5];
        [self addTarget:self action:@selector(changeShowing) forControlEvents:UIControlEventTouchUpInside];
        [self refreshSelfUI];
    }
    return self;
}

- (void)refreshSelfUI{
    NSString *titleStr = @"";
    DownMenuTitle *menuObj = [self.titleList objectAtIndex:self.curIndex];
    titleStr = menuObj.titleValue;
    CGFloat titleWidth = [titleStr getWidthWithFont:self.titleLabel.font constrainedToSize:CGSizeMake(kScreen_Width, 30)];
    CGFloat btnWidth = titleWidth +kNavImageWidth;
    self.frame = CGRectMake((kScreen_Width-btnWidth)/2, (44-30)/2, btnWidth, 30);

    self.titleEdgeInsets = UIEdgeInsetsMake(0, -kNavImageWidth, 0, kNavImageWidth);
    self.imageEdgeInsets = UIEdgeInsetsMake(0, titleWidth, 0, -titleWidth);
    [self setTitle:titleStr forState:UIControlStateNormal];
    [self setImage:[UIImage imageNamed:@"nav_arrow_down"] forState:UIControlStateNormal];
}

- (void)changeShowing{
    [kKeyWindow endEditing:YES];
    
    if (!self.myTableView) {
        //定义其显示的位置
        self.myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0,64, kScreen_Width, 0) style:UITableViewStylePlain];
        [self.myTableView registerClass:[DownMenuCell class] forCellReuseIdentifier:kCellIdentifier_DownMenu];
        self.myTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        self.myTableView.dataSource = self;
        self.myTableView.delegate = self;
        self.myTableView.alpha = 0;
        self.myTableView.scrollEnabled = NO;
    }
    if (!self.myTapBackgroundView) {
        self.myTapBackgroundView = [[UIView alloc] initWithFrame:kScreen_Bounds];
        self.myTapBackgroundView.backgroundColor = [UIColor clearColor];
        UITapGestureRecognizer *bgTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(changeShowing)];
        [self.myTapBackgroundView addGestureRecognizer:bgTap];
    }
    
    if (self.isShowing) {//隐藏
        CGRect frame = self.myTableView.frame;
        frame.size.height = 0;
        self.enabled = NO;
        [UIView animateWithDuration:0.3 animations:^{
            [self refreshSelfUI];
            self.myTapBackgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0];
            self.myTableView.alpha = 0;
            self.myTableView.frame = frame;
            self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, DEGREES_TO_RADIANS(180));
        } completion:^(BOOL finished) {
            [self.myTableView removeFromSuperview];
            [self.myTapBackgroundView removeFromSuperview];
            self.enabled = YES;
            self.isShowing = !self.isShowing;
        }];
    }else{//显示
        [[UIApplication sharedApplication].keyWindow addSubview:self.myTapBackgroundView];
        [[UIApplication sharedApplication].keyWindow addSubview:self.myTableView];
        [self.myTableView reloadData];
        CGRect frame = self.myTableView.frame;
        frame.size.height = kDownMenuCellHeight *[self.titleList count];
        self.enabled = NO;
        [UIView animateWithDuration:0.3 animations:^{
            self.myTapBackgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2];
            self.myTableView.alpha = 1.0;
            self.myTableView.frame = frame;
            self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, DEGREES_TO_RADIANS(180));
        } completion:^(BOOL finished) {
            self.enabled = YES;
            self.isShowing = YES;
        }];
    }
}

#pragma mark Table M
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return [self.titleList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    DownMenuCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier_DownMenu forIndexPath:indexPath];
    DownMenuTitle *curItem =[self.titleList objectAtIndex:indexPath.row];
    cell.curItem = curItem;
    cell.backgroundColor = (indexPath.row == self.curIndex)? [UIColor colorWithHexString:@"0xf3f3f3"] : [UIColor whiteColor];
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return kDownMenuCellHeight;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    self.curIndex = indexPath.row;
    [self changeShowing];
    if (self.menuIndexChanged) {
        self.menuIndexChanged([self.titleList objectAtIndex:_curIndex], _curIndex);
    }
}

- (void)setCurIndex:(NSInteger)curIndex{
    _curIndex = curIndex;
    [UIView animateWithDuration:0.3 animations:^{
        [self refreshSelfUI];
//        [self.myTableView reloadData];
//        [self.myTableView performSelector:@selector(reloadData) withObject:nil afterDelay:0.3];
    }];
}

- (void)dealloc
{
    self.myTableView.delegate = nil;
}

@end


@implementation DownMenuTitle
+ (DownMenuTitle *)title:(NSString *)title image:(NSString *)image badge:(NSString *)badge{
    DownMenuTitle *menuObj = [[DownMenuTitle alloc] init];
    menuObj.titleValue = title;
    menuObj.badgeValue = badge;
    menuObj.imageName = image;
    return menuObj;
}
@end

其中refreshSelfUI这个方法里面是实现的选择时,对应文字跟箭头图标的变化;重点的内容在changeShowing这个方法,它有定义列表要显示的位置,列表的创建初始化,及背景模态的出现,显示及隐藏的内容,视图的创建及删除;最后一个是实体的赋值;

4:表格单元行的布局DownMenuCell,主要代码如下:

#define kCellIdentifier_DownMenu @"DownMenuCell"

#import <UIKit/UIKit.h>
#import "UIDownMenuButton.h"
#import "UIColor+expanded.h"

@interface DownMenuCell : UITableViewCell
@property (strong, nonatomic) DownMenuTitle *curItem;
@end
#import "DownMenuCell.h"

@implementation DownMenuCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
    }
    return self;
}

- (void)awakeFromNib
{
    // Initialization code
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}
- (void)layoutSubviews{
    [super layoutSubviews];
    if (!_curItem) {
        return;
    }
    self.imageView.frame = CGRectMake(27, (50.0-25.0)/2, 25, 25);
    self.textLabel.frame = CGRectMake(65, (50.0-25.0)/2, 150, 25);
    self.textLabel.backgroundColor = [UIColor clearColor];
    self.textLabel.textColor = [UIColor blackColor];
    self.textLabel.font = [UIFont systemFontOfSize:15];
    
    self.imageView.image = [UIImage imageNamed:_curItem.imageName];
    self.textLabel.text = _curItem.titleValue;;
}
@end

 

转载于:https://www.cnblogs.com/wujy/p/4712329.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 下拉框三级联动是一种常见的前端交互方式,可以通过AJAX实现。具体实现步骤如下: 1. HTML布局:使用select标签实现三个下拉框 ```html <select id="province"> <option value="">请选择省份</option> </select> <select id="city"> <option value="">请选择城市</option> </select> <select id="district"> <option value="">请选择区县</option> </select> ``` 2. JavaScript代码:使用jQuery库实现AJAX请求和DOM操作 ```javascript $(function(){ // 获取省份列表 $.ajax({ url: 'province.php', type: 'get', dataType: 'json', success: function(data){ // 遍历省份列表,添加到下拉框中 $.each(data, function(index, item){ $('#province').append('<option value="' + item.id + '">' + item.name + '</option>'); }); } }); // 省份下拉框改变事件 $('#province').change(function(){ var provinceId = $(this).val(); if(provinceId){ // 获取城市列表 $.ajax({ url: 'city.php', type: 'get', data: {provinceId: provinceId}, dataType: 'json', success: function(data){ // 清空城市和区县下拉框 $('#city').empty().append('<option value="">请选择城市</option>'); $('#district').empty().append('<option value="">请选择区县</option>'); // 遍历城市列表,添加到下拉框中 $.each(data, function(index, item){ $('#city').append('<option value="' + item.id + '">' + item.name + '</option>'); }); } }); }else{ // 清空城市和区县下拉框 $('#city').empty().append('<option value="">请选择城市</option>'); $('#district').empty().append('<option value="">请选择区县</option>'); } }); // 城市下拉框改变事件 $('#city').change(function(){ var cityId = $(this).val(); if(cityId){ // 获取区县列表 $.ajax({ url: 'district.php', type: 'get', data: {cityId: cityId}, dataType: 'json', success: function(data){ // 清空区县下拉框 $('#district').empty().append('<option value="">请选择区县</option>'); // 遍历区县列表,添加到下拉框中 $.each(data, function(index, item){ $('#district').append('<option value="' + item.id + '">' + item.name + '</option>'); }); } }); }else{ // 清空区县下拉框 $('#district').empty().append('<option value="">请选择区县</option>'); } }); }); ``` 3. 服务器端代码:根据省份和城市的ID获取对应的城市和区县列表,返回JSON格式数据 省份列表查询代码(省份表结构:id、name): ```php <?php // 连接数据库 $conn = mysqli_connect('localhost', 'root', '123456', 'test'); mysqli_set_charset($conn, 'utf8'); // 查询省份列表 $sql = 'select id, name from province'; $result = mysqli_query($conn, $sql); $data = array(); while($row = mysqli_fetch_assoc($result)){ $data[] = $row; } // 返回JSON格式数据 header('Content-Type: application/json; charset=utf-8'); echo json_encode($data); mysqli_close($conn); ?> ``` 城市列表查询代码(城市表结构:id、name、province_id): ```php <?php // 连接数据库 $conn = mysqli_connect('localhost', 'root', '123456', 'test'); mysqli_set_charset($conn, 'utf8'); // 获取省份ID $provinceId = $_GET['provinceId']; // 查询城市列表 $sql = 'select id, name from city where province_id = ' . $provinceId; $result = mysqli_query($conn, $sql); $data = array(); while($row = mysqli_fetch_assoc($result)){ $data[] = $row; } // 返回JSON格式数据 header('Content-Type: application/json; charset=utf-8'); echo json_encode($data); mysqli_close($conn); ?> ``` 区县列表查询代码(区县表结构:id、name、city_id): ```php <?php // 连接数据库 $conn = mysqli_connect('localhost', 'root', '123456', 'test'); mysqli_set_charset($conn, 'utf8'); // 获取城市ID $cityId = $_GET['cityId']; // 查询区县列表 $sql = 'select id, name from district where city_id = ' . $cityId; $result = mysqli_query($conn, $sql); $data = array(); while($row = mysqli_fetch_assoc($result)){ $data[] = $row; } // 返回JSON格式数据 header('Content-Type: application/json; charset=utf-8'); echo json_encode($data); mysqli_close($conn); ?> ``` 以上代码仅供参考,具体实现需要根据实际情况进行调整。 ### 回答2: Ajax实现下拉框三级联动的主要步骤如下: 1. 配置HTML页面:在HTML页面中创建三个下拉框的元素,并分别设置一个id,用于后续的JavaScript操作。 2. 编写JavaScript代码:使用JavaScript监听第一个下拉框的改变事件。当第一个下拉框选中的选项发生改变时,触发事件处理程序。 3. 使用Ajax发送异步请求:在事件处理程序中,使用Ajax发送异步请求到服务器,以获取与第一个下拉框选中选项相关联的第二个下拉框选项。 4. 服务器端处理请求:服务器端根据第一个下拉框选中的选项,查询数据库或者调用API,获取与之相关联的第二个下拉框选项,并将数据以JSON格式返回给前端。 5. 更新第二个下拉框选项:前端接收到服务器返回的数据后,使用JavaScript动态添加或替换第二个下拉框选项。 6. 同样地,在第二个下拉框的改变事件中,触发事件处理程序,并通过Ajax发送异步请求获取与第二个下拉框选中选项相关联的第三个下拉框选项。 7. 更新第三个下拉框选项:前端接收到服务器返回的数据后,使用JavaScript动态添加或替换第三个下拉框选项。 通过以上步骤,就可以实现下拉框的三级联动效果。需要注意的是,要正确处理在选择某个下拉框选项时,下级下拉框选项需要相应改变。另外,在发送Ajax请求时需要考虑兼容性和请求的性能,可以使用jQuery等库来简化代码,并提高发送请求的效率。 ### 回答3: Ajax实现下拉框三级联动的原理是通过前端页面的JavaScript代码和后端服务器之间的异步请求来实现数据的动态加载和更新。 首先,我们需要创建三个下拉框元素,分别用于显示一级、二级和三级的选项。通过监听一级下拉框的变化事件,我们可以在JavaScript代码中获取到用户选择的一级选项的值。 接下来,我们需要使用Ajax技术向后端服务器发送异步请求,获取对应一级选项的二级选项数据。通过Ajax发送GET或POST请求,并将一级选项的值作为参数传递给后端服务器,服务器根据参数的值查询数据库或其他数据源,返回对应的二级选项数据。 当从服务器端获取到二级选项数据后,我们可以使用JavaScript动态地更新二级下拉框选项。此时,我们同样需要监听二级下拉框的变化事件,以获取用户选择的二级选项的值。 然后,我们再次使用Ajax技术向后端服务器发送异步请求,获取对应二级选项的三级选项数据。服务器根据二级选项的值查询数据库或其他数据源,返回对应的三级选项数据。 当从服务器端获取到三级选项数据后,我们可以使用JavaScript动态地更新三级下拉框选项。 通过以上操作,我们就可以实现下拉框的三级联动效果。用户选择一级选项后,二级选项会根据一级选项的值进行动态更新;用户选择二级选项后,三级选项会根据二级选项的值进行动态更新。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值