碧海晴空——三亚行

假如您与自身同一,工作了平等年半,相信你吧涉了几只大本的迭代开发,甚至有所几个利用的支付经历。那么当贯彻了那基本上复杂的事务逻辑下,你道,利用纯代码,怎么样去创造一个怡然自得、优、简以及便于管理的核心框架为?
这半龙在思索这个问题,于是起矣以下想法(可能还未是杀熟,如果您产生再好的想法,请评论报自己,在此提前感谢)。

     
有时候去同所都旅行,不自然要是计划非常遥远,也许就算那说话因在地铁及看了看某旅行APP,也许还是那么片单人,也许最终就改为四人执行了,so
 easy!

撸撸思路

今盖追加建筑一个类型的中心框架为例,来讨论这个问题,最终之法力图如下:

图片 1

著力量

大家好看到,这真的是一个犬牙交错项目的底蕴,即使逻辑又繁杂的界面,最开始吧还是由这界面起步的,而对于它,我们要举行的:

  • 初始化几个子控制器
  • 增补加起定义的 TabBarView
  • 补加起定义的 NavigationBar
  • 补充加于自然的 TopBarColumnView

     
来来来,各位搬来小板凳,开始此次三亚行的回顾,希望要失去之都能够吸取点精华。

未雨绸缪干活

这边要是准备一些项目支付要之资源同增长一些亟待使用及之老三方库,过程简单、琐碎:

  • 导入需要运用及的漫天图资源
  • 导入需要以到的老三正值: RxSwift、RxCocoa
  • 结合 UIStoryBoard
    初始化几只控制器,并当每个控制器上加加初始化显示图片

成就上述操作下,可得种结构如下:

目录名称 功能介绍
Main 项目的主要入口
Main – MenuViewController 菜单控制器,作用与 TabBarController 相同
Business 存储所有的业务逻辑模块
Business – Home 首页业务模块
Business – Medium 书影音 业务模块
Business – Broadcast 广播 业务模块
Business – Group 小组 业务模块
Business – Profile 我的 业务模块
Utility 存储所有的功能模块
Utility – Extension 存储所有功能类的功能扩展

自,大家认为无聊就径直跨越了之操作,在 github 上
https://github.com/iJudson/RxBasicInterface.git
<初期准备> 该 commit 上一直用到即同一步之代码

     人员:4丁(表哥表嫂堂姐我)

正题

得了了有的准备工作,接下进入正题:使用 RxSwift 创建 TabBarView
供菜单控制器 MenuViewController 使用

     天数:5龙4后(精确点就4独白天4独夜晚)

TabBarView 的创建

事实上对某些 View
的使用,即使是上下一心创办的,往往会以过了相同段于丰富的流年过后,再错过采用就张
View 时,竟然发现不能下手,需要再次重复下代码,特别是对那些专门复杂的
View,有差不多个有利构造函数,或者特别多之旁控件,而且需要基于不同状况去行使中的少数控件…
还有一样种情况,
你在信用社跟其他人协同工作时,会无见面发现而去下及外创造的比较复杂的 View
时,需要或有时日,感到特别累啊?
对当时点儿只问题,我之解决方案是:

<创办该 View 专属的样式类>
于此,你可以先行失和你的同事还是与自己约定一法创建 View
的作风,就是在开创该 View 的上先失创造该 View 的专属样式类:用于管理该
View 的富有样式:颜色、子控件类型和数目、子控件的示位置…
咱俩怀念创立 TabBarView,让咱先行来创造 TabBarView 的体管理类:

typealias TabBarItemElement = (normalImage: UIImage?, selectedImage: UIImage?, title: String?)

// TabBarView 的样式管理类
struct TabBarStyle {
    //  子控件的元素集合   
    var itemElements: [TabBarItemElement]
     //  TabBarView 的颜色主题(默认为白色)   
    var themeColor: UIColor = UIColor.white
    //  是否含有顶部分割线   
    var hasTopLine: Bool = true
    // 在初始化构造器中,只去初始化必要的元素,避免初始化构造器过于冗长
    init(elements: [TabBarItemElement] = []) {
        self.itemElements = elements
    }
}

<创建 TabBarView>
起矣端的样式管理类,我们当该 View
中,对外的习性就专门少,基本就是惟有区区只,这为大程度的增强了该 View
的封装性。
1. 定义对外的样式属性:

// 主题样式
var themeStyle: TabBarStyle = TabBarStyle() {
    didSet {
        // 通过属性监视器,外部可以通过该属性更新 TabBarView 的整体样式
        update(ThemeStyle: themeStyle)
    }
}

2. 创建好构造函数:便于外部对此类的下

convenience init(frame: CGRect? = nil, themeStyle: TabBarStyle) {
    // 当外部不传入 Frame 值时,我们默认使用以下 Frame 值
    let barFrame = frame ?? CGRect(x: 0, y: screenHeight - tabBarHeight, width: screenWidth, height: tabBarHeight)
    self.init(frame: barFrame)
    // 设置背景颜色
    self.backgroundColor = themeStyle.themeColor
    // 根据样式管理类,更新该 view 的主体样式
    update(ThemeStyle: themeStyle)
    // 根据样式管理类,决定是否添加顶部分割线
    add(TopLine: themeStyle.hasTopLine)
}

OK,到此是 View
大体上就是创造了了。是休是可怜粗略,日后凡是免是为很便于管理?目前来拘禁,这个
View 只发生一个对外属性,还有一个 convenience
构造函数,确实特别便宜我们管理,而对样式,我们唯有需要去查样式管理类,就只有这个
View 的拥有的样式…
哈,其实接下,还是来几细节要连续到。

3. 实现样式更新的办法
每当里边,我们仅仅待用到表面传进的体属性,去创新样式。
以此的 TabBarItem
既来图片,又出题目,所有外部需要以立即有限只属性都招进。

fileprivate func update(ThemeStyle style: TabBarStyle) {
    // 所有的样式元素数量
    let itemCount = style.itemElements.count
    let itemWidth = screenWidth/itemCount
    var commonItemFrame = CGRect(x: 0, y: 0, width: itemWidth, height: tabBarHeight)
    // 通过 for 循环,将拿到的所有元素遍历添加到 TabBarView 上
    for (index, element) in style.itemElements.enumerated() {
        commonItemFrame.origin.x = index * itemWidth
        let commonTabBarIem = CommonItemView(frame: commonItemFrame, image: element.normalImage, title: element.title)
        commonTabBarIem.setImage(element.selectedImage, for: .selected)
        commonTabBarIem.alignmentStyle = .upImageDownText(space: 2)
        commonTabBarIem.tag = index
        commonTabBarIem.titleLabel?.font = UIFont.systemFont(ofSize: 12)
        commonTabBarIem.setTitleColor(UIColor.gray, for: .normal)
        commonTabBarIem.setTitleColor(UIColor.black, for: .selected)

        self.addSubview(commonTabBarIem)
        // 这里我们添加监听者,监听每一个 Item 的点击操作,当 item 被点击时,我们通过 Driver 序列,发送点击事情到这和序列上
        let selectedIndex = commonTabBarIem.rx.controlEvent(.touchDown).throttle(0.5, scheduler: MainScheduler.instance).flatMapLatest { (_) -> Driver<Int> in
            return Driver<Int>.just(commonTabBarIem.tag)
            }.asDriver(onErrorJustReturn: 0)
        // 对外监听属性的集合 
        selectedIndexes.append(selectedIndex)

        // 默认选中第一个 tabBarItem
        commonTabBarIem.isSelected = (index == 0 ? true : false)
    }
}

于点方法中,大家应该产生留意到,我们得一个对外监听属性的集聚,监听用户之点击操作,因为相似
TabBar 有5独 Item,故而这个集一般还来五单对外监听属性,属性定义如下:

 //当前选中的 index
 var selectedIndexes: [Driver<Int>] = []

4. 添加顶部分割线

 fileprivate func add(TopLine isExisting: Bool) {
    // 事先判断是否需要添加分割线,如果不需要,可直接 return 返回
    guard isExisting else {
        return
    }

    let lineHeight: CGFloat = 0.5
    let topLine = UIView(frame: CGRect(x: 0, y: -lineHeight, width: screenWidth, height: lineHeight))
    topLine.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.3)
    self.addSubview(topLine)
 }

顶就无异于步之代码,大家可以当
https://github.com/iJudson/RxBasicInterface
<创建 TabBarView> 当前 commit 上获取(注意,现在当这个 commit
上运行程序,还是没有其他意义,毕竟还并未以到该 TabBarView)

三亚程汇总

TabBarView 在 MenuViewController 的使用

TabBarView 是当 MenuViewController 去动的, 在 MenuViewController
中吗急需去监听 TabBarView 的 selectedIndexes 数组属性,从而监听到
TabBarView 上之点击操作。而事实上,TabBarView 的使,由于使用了 RxSwift
,也转移得特别简单,也方便管理。
1. 我们在 viewDidLoad 添加有数单办法

  • 初始化 MenuViewController
    中有所的分段控制器,并默认为首页控制器显示在主页上
  • 安排底部 TabBarView ,创建所急需样式管理类
    TabBarViewStyle,并补充加所需要元素

 override func viewDidLoad() {
    super.viewDidLoad()

    initializeTopViewControllers()

    configureTabBar()
 }

属下,我们仅需要定义并完善上述两单方法…

2. 初始化所有的旁控制器

 fileprivate func initializeTopViewControllers() {
     // 通过 UIStoryboard 拿到所有的子导航控制器
    let homeNav = UIStoryboard.NavigationController.home
    let mediumNav = UIStoryboard.NavigationController.medium
    let broadcastNav = UIStoryboard.NavigationController.broadcast
    let groupNav = UIStoryboard.NavigationController.group
    let profileNav = UIStoryboard.NavigationController.profile
    // 并预先添加到 topViewControllers 数组中,当点击某一个 TabBarItem 时,根据需要添加具体的控制器
    topViewControllers = [homeNav, mediumNav, broadcastNav, groupNav, profileNav]

    // 初始化时,默认添加首页控制器
    self.addChildViewController(homeNav)
    homeNav.view.frame = self.view.bounds
    self.view.addSubview(homeNav.view)
    // 默认显示首页控制器
    self.selectedViewController = homeNav
    // 更新状态栏的状态
    self.setNeedsStatusBarAppearanceUpdate()
 }

3. 配置 TabBarView,监听其中的点击属性

  • 俺们以到所有的图纸与标题属性
  • 配备 TabBar 样式管理类
  • 监听TabBarItem 的点击操作(这里由于 RxSwift 会变得专程简单)
  • 拍卖 TabBarItem 的点击事件

 fileprivate func configureTabBar() {
    // 拿到五个 BarItem 上的元素(图片和标题)
    let barItemElements: [TabBarItemElement] = [
        (normalImage: UIImage(named: "ic_tab_home_gray_32x32_"), selectedImage: UIImage(named: "ic_tab_home_32x32_"), title: "首页"),
        (normalImage: UIImage(named: "ic_tab_subject_gray_32x32_"), selectedImage: UIImage(named: "ic_tab_subject_32x32_"), title: "书影音"),
        (normalImage: UIImage(named: "ic_tab_timeline_gray_32x32_"), selectedImage: UIImage(named: "ic_tab_timeline_32x32_"), title: "广播"),
        (normalImage: UIImage(named: "ic_tab_group_gray_32x32_"), selectedImage: UIImage(named: "ic_tab_group_32x32_"), title: "小组"),
        (normalImage: UIImage(named: "profile_normal_32x32_"), selectedImage: UIImage(named: "profile_active_32x32_"), title: "我的")
    ]
    // 创建管理样式类
    let tabBarStyle = TabBarStyle(elements: barItemElements)
    // 拿到样式类,创建 TabBarView 
    let tabBarView = TabBarView(themeStyle: tabBarStyle)
    self.view.addSubview(tabBarView)
    // 监听 TabBarView 的 selectedIndexes 属性,当有点击操作时,触发处理点击事件的方法
    for selectedIndex in tabBarView.selectedIndexes {
        selectedIndex.drive(onNext: { [weak self] (index) in
            guard let strongSelf = self else {
                return
            }
            // 处理点击事件
            strongSelf.handleTopControllerSelectionEvent(currentIndex: index)

        }).disposed(by: disposeBag)
    }
 }

倘那个点击事件的处理如下:

fileprivate func handleTopControllerSelectionEvent(currentIndex: Int) {
   // 移除上一次选择的控制器
    if let selectedViewController = selectedViewController {
        selectedViewController.willMove(toParentViewController: nil)
        selectedViewController.view.removeFromSuperview()
        selectedViewController.removeFromParentViewController()
        selectedViewController.viewWillDisappear(false)
    }
    // 添加当前选择的控制器,并显示
    let currentSelectedViewController = topViewControllers[currentIndex]
    self.addChildViewController(currentSelectedViewController)
    currentSelectedViewController.view.frame = self.view.bounds
    self.view.addSubview(currentSelectedViewController.view)
    currentSelectedViewController.didMove(toParentViewController: self)
    self.selectedViewController = currentSelectedViewController
    self.setNeedsStatusBarAppearanceUpdate()
    self.selectedIndex = currentIndex

    // 置顶 TabBar
    for subView in self.view.subviews {
        if let tabBar = subView as? TabBarView {
            self.view.bringSubview(toFront: tabBar)
        }
    }
}

OK,到此,我们一个大概的种类框架就已经完结,其作用如下:

图片 2

BasicInterface.gif

您得当
https://github.com/iJudson/RxBasicInterface
<TabBarView 在 MenuViewController 的使用>
的道岔上用到至今的代码。

1.旅行前准备篇

     
以上是本身排的4日总行程,基本包含了三亚大部分底风物。因此次是4丁尽,好歹也得以让一个小团了咔嚓!表哥表嫂也是首先坏和咱们自由行,希望他们打的几近点,欣赏的吗多点。

     
 亲们,千万不要小瞧我们当下团,分工明细啊,我是团长,负责所有行程计划、机票与酒店预订;堂姐是会计师兼导游,负责旅行中各个景点门票、滴滴打车、吃饭买单、机票领取、记账、身份证管理等;表哥表嫂就是VIP客户啊,我们的上帝呀,一定要是服务好啊!

     
 先说说订机票及酒吧,以及选景点。建议大家手机上大多生几慢慢悠悠旅行APP(如蚂蜂窝,飞猪,途牛,去何方,驴妈妈当)。

     
 关于机票,我只好放假4上,综合大家的年华,就确定了11月27日—11月30日4上,接下去就摸索11月26日6点之后失去的航班及11月30日午后转之航班,找到最深性价比做的。

     
 关于酒店,先在蚂蜂窝上基本上看看别人去三亚之掠影,把精华都记下来,然后度娘了解一下三亚之地图,看看三亚产生哇几大湾(著名的),以机场也原点,从接近及多或者打远及近,先消除下。如机场——三亚湾——大东海——亚龙湾——海棠湾

先期看这几大湾内部有怎么样景点,都先记下来,再因呆的岁月长(我们只能去4天)综合取舍好酒店(建议选择2独酒店),因此自选的2单酒店一个于三亚湾(阳光大酒店),一个当海棠湾(御海棠豪华度假酒店)。

关于景点,再冲选好之酒吧,选出最亟需去之景物,以阳光大酒店也圆点,规划2天路,再根据御海棠酒店为圆点规划2龙路。

后续

当一个简易的类型框架还非只有这些或许会见出:

  • 导航栏 – NavigationBar
  • 顶部选栏 – TopBarColumnView

如立片只 View 的创始与 TabBarView
的创建是千篇一律型一样的,大家还试着去创造体会下。我此也不再赘余,而最后的效力如下:

图片 3

Last Version BasicInterface.gif

末了之代码,大家可以当
https://github.com/iJudson/RxBasicInterface
中找到。

如果这个基本框架还有哪些地方可以继承优化,请不吝评论报自己。
倘若你认为这核心框架还不易,欢迎 star。

感谢!

2.每天行程细说篇

        11月26日即从未什么好说的了。入住休息。

       
第一天(11月27日)行程看起或要命满之,一个白天若是错过3独地方。但是咱联系了接机的师父,前一天接机的路上聊了一下,一上300首位,跟咱们一致天,我们进景区,他于外围当正,一直到吃了饭送我们回酒店,4单人口终于下来或者特别划算的,所以放心大胆的玩呗。

11月27日清晨痊愈,掀开窗帘看到前面的汪洋大海,那心情真的激动啊,第一不良看见大海啊!直接上图什么!阳光大酒店的180度海景房,确实蛮美!

酒吧海景

率先站先失南山文化区,也即是南山寺,首当其冲要拘留的即使是那尊海上观音,我尚未打大佛全景照,网上搜索了相同摆放,借用一下啊!

海上观音

     
 海上观音总共三迎,每一样当观音手中所持之东西都无一样的,正面是“持箧观音”,右面是“持珠观音”,左面是“持莲观音”,分别寓意在“智慧、慈悲、和平”。观音足下的芙蓉宝座,也是深秀气的高十米,共四重合,每层有相相同的二十七瓣莲花花,共一百零八瓣,也是由全钛合金打造。

       
据说,之前灾害很多,诸如台风水灾,从海上观音建成后,灾害少了众,所以大家对海上观音都怪尊敬啊。据说在海南三亚凤凰机场起降的航班,都见面以南海观音上空绕一环抱,建议大家为于机右侧,可以省。我是夜间届之,没顾什么!

咱爬至4层,看到的风物还是大得意啊!我光顾赏了,没拍啊,大家网上去搜搜啊!不过起一致张或蛮有意思的,这即是传说被之抱佛脚吧!

抱佛脚

咱第一去矣海上观音,其余都是盖浏览车逛的。

中午于南山寺其中吃的素菜,还不错,做下的东西还分外逼真的

吃素

下午错过了千山万水,大概逛了2.3小时,因为自然了三亚千古情6点的表演门票。

三亚仙逝情景区,主要看了表演是1钟头,因为事先以丽江关押罢丽江病逝情,看了三亚千古情,觉得还是蛮有风味之。推荐大家去看啊,照片便非达了。

大致到夜间7点半出去,司机接我们错过吃海鲜大餐,没有失去大家还推荐的率先市场,而是去了下岗职工海鲜市场,司机师傅跟我们同去挑的海鲜,一起探寻的加工,海鲜很对,也未值钱,但是海鲜加工价都逮得上海鲜价了!

晚上9点半扭酒店,今日路途是完结了,还有平等宗事,今天凡表哥的八字,感谢万能的外卖,10点多就是搞好一个蛋糕送及到酒楼了,在大酒店泳池处了了一个坏难忘的生日!

次天(11月28日)还是于的切削以及同样上,睡到7点半起床,打包行李,去吃酒店提供的早饭,早餐非常好,然后起身去亚龙湾热带森林公园,非诚勿扰2的拍摄地。

山上风景非常得意,手机打不闹那种效果啊,凑合看看啊,下掉有门确乎要考虑买入个专业相机了。中午当山上吃的自租餐,都富含在门票,电瓶车,中午饭,过索桥里面了,还不曾经济的。

   
下午2点基本上钟,去了南田温泉,南田温泉是我国最特别之户外温泉,被号称“神州第一元”。

南田温泉依山傍水,属低温温热矿水,水温56℃,矿化度很高。温泉含有多种针对性人体有益的矿物质与微量元素。这种温泉水可以舒筋活络,对血肉之躯多病症生新鲜之辅疗效,带吃体验者强身健体的自享受。南田温泉共发出34个温泉池,包括小鱼温泉等,分布在原椰林中,一池一现象。

     
 第一坏夏天泡温泉,有的泉温度都非高哦,小鱼温泉很风趣的,有许多老外在中泡温泉,我哥腿上饶痒的成千上万划痕,都吉祥如意了,有接触吓人啊!泡了此处的温泉,第二天禁闭腿上,只出浅色痕迹了,看来要生硌用底哟,什么枸杞温泉,中药温泉都好泡泡,还有一个推浪温泉吧,也蛮有意思的。同志等,温泉也不宜久泡,泡十几分钟就起,我们以温泉区呆到5点基本上。然后就夺海棠湾国宾馆。

注意什么,三亚之酒楼都是12点交房,下午3点才会适合息的,咱们多5点半到的,海棠湾御海棠豪华度假酒店,我肯定要是碰单赞,服务专门好,还有酒店房间特别怪,我们入住的是向海阁。拍的是大床房的影啊,具体大家好错过网站及搜搜一下这家酒店。

夜约逛了一晃酒吧,点了外卖海鲜,洗洗睡吧。这么出色的酒吧,这么nice的房间,做个好梦啊!

     
 第三天呢就是是11月29日失去矣蜈支洲岛,酒店去海棠湾还是十分贴近的,早上咱们给了滴滴到码头,坐船上了汀,这个岛屿海水特别绝望,可以各种潜水项目。也是自己人订制的拍照地,具体大家百度瞬间哟!

俺们从来不打项目,随意地逛逛小岛屿,小岛屿上各一样地处还是山水,最记得的便是即时海滩上之海水,太清了。如果自身一个口,就这么于海边呆一天也是好的。

       
我们直接发呆到下午1点多去岛,接下去去矣海棠湾免税购物为主,亲,千万不要低估女人之购买力,更何况我们中还来只购物狂,原定去免税店逛逛1.2时就回酒店,结果就是以化妆品区至少呆了4单多时,连自家还无准备进东西的人,都请了平单口红,一盒气垫BB霜,后来我真站不下来了,太难为了,跟自己哥去休息区休息,另外两人口尚当化妆区奋战啊!太吓人了!

       
在这里特别要取一下免税中心的方针,我们是入住的那天联系酒店做好登记,酒店会见管记录报给免税中心,去购物会时有发生一个9.5折优惠,需要超前一天的15:00前同小吃摊礼宾部预约,有一个金额限制的,一摆放身份证限额是15000处女,化妆品类是无可知跨越12项的,我们报了名了少数张身份证。去免税店购买了化妆品后,是免能够一直将走的,(也闹就购买就算提,好像交担保金什么的,我们是直去机场取之)他们会以及你保存,直接送及机场,等您离开三亚那天,去矣飞机场过了安检后一直去免税物品提取处达飞机的。 

夜里回酒店,真是一点还非思动了,化妆品区之总人口最好多矣,特别是部分大牌,如迪奥,雅诗兰黛,兰蔻,女人之购买力真是不可知小视啊!

     
 11月30日,哎,真快啊!最后一龙了哟,早上凭着了酒吧的自助早餐,把酒楼良好逛了游,因为我们住的酒楼同附近的欣赏来登酒店都属于喜上屋旗下之,酒店设施都是官的。酒店的知心人海滩特别大,海棠湾底海边浪特别酷,不合乎游泳,但是关押正在平等浪一浪的海水过来特别舒服,开心。谁为自己是未曾见了大海之人啊!废话不多说,直接上照片!

咱住的望海阁

       
收拾收拾行李,回家了什么,酒店有免费大巴送我们到机场,真恩爱,我们是下午4点飞机,坐的是1点10分叉的大巴,到了机场,取票,进安检,拿化妆品,上飞机,真是得,中间还无浪费时间的,至此,此次大格的三亚自由行,到处结束了。

     
 我之感想就是岁月最缺了,三亚确实适合每年还失去同回的地方,找个因海的小吃摊,啥事乎未干,看看海,躺在海边的交椅上,这生活喽的几近看中啊!
                                                      

      所以回去好好赚钱,来年再见,三亚!

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注