iOS开发之旅(1):实现一个APP界面框架

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shenjie12345678/article/details/76522223

在上一篇博客中,给大家介绍了一下我们传统的 APP 界面框架—标签导航的一些优缺点,在这篇文章中我会来给大家演示,如何用代码去实现这一框架。本次的实现我会分成俩部分来讲,好了闲话少说,接下来进入到开发阶段。

先来一张最终的效果图瞅一眼:

这里写图片描述

接下来,创建一个 Xcode 工程,我取名叫做CoolFrame,该项目我到时候会托管到 GitHub 上去维护,地址我会在下一篇博文中给出。

根据上图的样式,可以把界面分成三部分:导航栏,中间内容,以及底部的TabBar。我们先从简单的中间内容开始编码做起,这里我根据我底部有四个tabbar,所以定义了四个UIViewController,每个UIViewController很简单,主要是为了能够区分我下方点击的是哪一个TabBarItem,每个UIViewController中都用一个固定的英文字母显示在正中央,这里就列举其中一个界面的代码:

#import "FirstViewController.h"

@interface FirstViewController ()

@end

@implementation FirstViewController
@synthesize label = _label;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.title = @"A";
    [self.view setBackgroundColor:[UIColor whiteColor]];

    [[self label] setFrame:CGRectMake(roundf(self.view.frame.size.width - 100)/2, roundf(self.view.frame.size.height - 100)/2, 100, 100)];

    [self.label setTextAlignment:NSTextAlignmentCenter];
    [self.label setFont:[UIFont fontWithName:@"HiraKakuProN-W3" size:40.0f]];
    [self.label setText:@"A"];

    [self.view addSubview:[self label]];
}

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

- (UILabel *)label{
    if(!_label){
        _label = [[UILabel alloc] init];
    }

    return _label;
}

@end

中间部分很简单,接下来咱们来说说底部的 tabbar 是怎么实现的,先来看下效果图:

这里写图片描述

我来把效果图构造拆分成四个 UIButton 和一个 UIView ,这样是不是就很容易明白了,UIView 作为一个背景框里面填补了四个按钮,当我们选中其中一个按钮的时候中间就切换到对应的界面,随后按钮的背景色也随之改变。当然,在这里我们要实现的可以一个可以用作商业用途的框架,所以说我们这里的按钮就不可能是 Xcode 给我们提供的按钮,我们得需要自定义一个按钮,这样才能让我们的 UI 更加的美观,好了,这里附上按钮的代码:

//
//  CustomTabBarItem.m
//  CoolFrame
//
//  Created by silicon on 2017/7/25.
//  Copyright © 2017年 com.snailgames.coolframe. All rights reserved.
//

#import "CustomTabBarItem.h"
#define RGB(r, g, b)                        [UIColor colorWithRed:(r)/255.f green:(g)/255.f blue:(b)/255.f alpha:1.f]
@implementation CustomTabBarItem

- (id)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if(self){
        [self commonInitialization];
    }

    return self;
}

- (id)init{
    return [self initWithFrame:CGRectZero];
}

- (void)commonInitialization{
    [self setBackgroundColor:[UIColor clearColor]];

    _title = @"";
    _titlePositionAdjustment = UIOffsetZero;
    _unselectedTitleAttributes = @{
                                   NSFontAttributeName: [UIFont systemFontOfSize:10],
                                   NSForegroundColorAttributeName: RGB(0, 0, 0)
                                   };
    _selectedTitleAttributes = [_unselectedTitleAttributes copy];
    _badgeBackgroundColor = [UIColor redColor];
    _badgeTextColor = [UIColor whiteColor];
    _badgeTextFont = [UIFont systemFontOfSize:12];
    _badgePositionAdjustment = UIOffsetZero;
}

- (void)drawRect:(CGRect)rect{
    CGSize frameSize = self.frame.size;
    CGSize titleSize = CGSizeZero;
    CGSize imageSize = CGSizeZero;
    NSDictionary *titleAttribute = nil;
    UIImage *backgroundimage = nil;
    UIImage *image = nil;
    CGFloat imageStartingY = 0.0f;

    if([self isSelected]){
        image = [self selectedImage];
        backgroundimage = [self selectedBackgroundImage];
        titleAttribute = [self selectedTitleAttributes];

        if(!titleAttribute){
            titleAttribute = [self unselectedTitleAttributes];
        }
    }else{
        image = [self unselectedImage];
        backgroundimage = [self unselectedBackgroundImage];
        titleAttribute = [self unselectedTitleAttributes];
    }

    imageSize = [image size];

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);


    [backgroundimage drawInRect:self.bounds];

    if(!_title){
        [image drawInRect:CGRectMake(roundf(frameSize.width / 2 - imageSize.width / 2) +
                                     _imagePositionAdjustment.horizontal,
                                     roundf(frameSize.height / 2 - imageSize.height / 2) +
                                     _imagePositionAdjustment.vertical,
                                     imageSize.width, imageSize.height)];
    }else{
        titleSize = [_title boundingRectWithSize:CGSizeMake(frameSize.width, 20)
                                         options:NSStringDrawingUsesLineFragmentOrigin
                                      attributes:@{NSFontAttributeName: titleAttribute[NSFontAttributeName]}
                                         context:nil].size;

        imageStartingY = roundf((frameSize.height - imageSize.height - titleSize.height) / 2);

        [image drawInRect:CGRectMake(roundf(frameSize.width / 2 - imageSize.width / 2) +
                                     _imagePositionAdjustment.horizontal,
                                     imageStartingY + _imagePositionAdjustment.vertical,
                                     imageSize.width, imageSize.height)];

        CGContextSetFillColorWithColor(context, [titleAttribute[NSForegroundColorAttributeName] CGColor]);

        [_title drawInRect:CGRectMake(roundf(frameSize.width / 2 - titleSize.width / 2) +
                                      _titlePositionAdjustment.horizontal,
                                      imageStartingY + imageSize.height + _titlePositionAdjustment.vertical,
                                      titleSize.width, titleSize.height)
            withAttributes:titleAttribute];
    }

    CGContextRestoreGState(context);
}

#pragma mark - Image configuration

- (UIImage *)finishedSelectedImage{
    return [self selectedImage];
}

- (UIImage *)finishedUnselectedImage{
    return [self unselectedImage];
}

- (void)setFinishedSelectedImage:(UIImage *)selectedImage withFinishedUnselectedImage:(UIImage *)unselectedImage{
    if(selectedImage && selectedImage != [self selectedImage]){
        [self setSelectedImage:selectedImage];
    }

    if(unselectedImage && unselectedImage != [self unselectedImage]){
        [self setUnselectedImage:unselectedImage];
    }
}

- (void)setBadgeValue:(NSString *)badgeValue{
    _badgeValue = badgeValue;
    [self setNeedsDisplay];
}

#pragma mark - Background configuration

- (UIImage *)backgroundSelectedImage{
    return [self backgroundSelectedImage];
}

- (UIImage *)backgroundUnselectedImage{
    return [self backgroundUnselectedImage];
}

- (void)setBackgroundSelectedImage:(UIImage *)selectedImage withUnselectedImage:(UIImage *)unselectedImage{
    if(selectedImage && selectedImage != [self selectedBackgroundImage]){
        [self setSelectedBackgroundImage:selectedImage];
    }

    if(unselectedImage && unselectedImage != [self unselectedBackgroundImage]){
        [self setUnselectedBackgroundImage:unselectedImage];
    }
}

@end

搞定了按钮,接下来就要把按钮聚集在一起,所以需要写一个按钮容器视图,不管有多少个按钮都可以让他们在这个容器中和谐的铺展开来,并且在这个类中,还要为按钮添加必要的响应事件,容器视图也是作为一个子视图存在,所以我们这边就定义一个 UIView 即可,具体代码如下:

#import <UIKit/UIKit.h>
#include "CustomTabBarItem.h"
@protocol CustomTabbarDelegate;

@interface CustomTarbar : UIView
@property (nonatomic, strong) id<CustomTabbarDelegate> delegate;
@property (nonatomic, strong) NSArray *items;
@property (nonatomic, strong) CustomTabBarItem *selectedItem;
@property (nonatomic, strong) UIView *backgroundView;
@property (nonatomic) CGFloat itemWidth;
@property (nonatomic) CGFloat miniContentHeight;

@end

@protocol CustomTabbarDelegate <NSObject>

- (BOOL)tabBar:(CustomTarbar *)tabBar shouldSelectItemAtIndex:(NSInteger)index;
- (void)tabBar:(CustomTarbar *)tabBar didSelectItemAtIndex:(NSInteger)index;

@end
//
//  CustomTarbar.m
//  CoolFrame
//
//  Created by silicon on 2017/7/25.
//  Copyright © 2017年 com.snailgames.coolframe. All rights reserved.
//

#import "CustomTarbar.h"

@implementation CustomTarbar
@synthesize delegate = _delegate;
@synthesize items = _items;
@synthesize selectedItem = _selectedItem;
@synthesize backgroundView = _backgroundView;
@synthesize miniContentHeight = _miniContentHeight;
@synthesize itemWidth = _itemWidth;

- (id)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if(self){
        [self commonInitlization];
    }

    return self;
}

- (id)init{
    return [self initWithFrame:CGRectZero];
}

- (void)commonInitlization{
    self.backgroundView = [[UIView alloc] init];
    [self addSubview:self.backgroundView];
}

- (void)layoutSubviews{
    CGSize framesize = self.frame.size;
    CGFloat height = self.miniContentHeight;

    [self.backgroundView setFrame:CGRectMake(0, framesize.height - height, framesize.width, framesize.height)];
    [self setItemWidth:roundf(framesize.width / self.items.count)];

    int index = 0;

    for (CustomTabBarItem *item in [self items]) {
        CGFloat itemHeight = item.itemHeight;
        if(!itemHeight){
            itemHeight = framesize.height;
        }

        [item setFrame:CGRectMake(self.itemWidth * index, framesize.height - height, self.itemWidth, itemHeight)];
        [item setNeedsDisplay];

        index++;
    }
}


#pragma mark - meathod
- (void)setItemWidth:(CGFloat)itemWidth{
    if(itemWidth > 0){
        _itemWidth = itemWidth;
    }
}

- (void)setItems:(NSArray *)items{
    _items = items;
    for(CustomTabBarItem *item in items){
        [item addTarget:self action:@selector(tabBarItemWasSelected:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:item];
    }
}

- (CGFloat)miniContentHeight{
    CGFloat minimumConentHeight = CGRectGetHeight(self.frame);
    for (CustomTabBarItem *item in [self items]) {
        CGFloat height = [item itemHeight];
        if(height && height < minimumConentHeight){
            minimumConentHeight = height;
        }
    }

    return minimumConentHeight;
}


#pragma mark -Item selection
- (void)tabBarItemWasSelected:(id)sender{
    if([[self delegate] respondsToSelector:@selector(tabBar:shouldSelectItemAtIndex:)]){
        NSInteger index = [self.items indexOfObject:sender];
        if(![[self delegate] tabBar:self shouldSelectItemAtIndex:index]){
            return;
        }
    }

    [self setSelectedItem:sender];

    if([[self delegate] respondsToSelector:@selector(tabBar:didSelectItemAtIndex:)]){
        NSInteger index = [self.items indexOfObject:self.selectedItem];
        [[self delegate] tabBar:self didSelectItemAtIndex:index];
    }
}

- (void)setSelectedItem:(CustomTabBarItem *)selectedItem{
    if(selectedItem == _selectedItem){
        return;
    }

    [_selectedItem setSelected:NO];
    _selectedItem = selectedItem;
    [_selectedItem setSelected:YES];
}

@end

到这里,我们的开发进度差不多已经完成了 50% ,但是我们的 App 还不能够顺利的运行起来,因为我们还缺一个视图控制类,我们前面开发完成了:主要内容界面,按钮以及存放按钮的容器,但这些类别都是单独存在的,我们需要一个组织者能够把他们串起来,这就要求我们还要再开发一个控制器类,那该如何下手呢!其实很简单,因为我们的按钮有自己的点击事件,只要能够告诉我们的控制器是哪个按钮点击了,那我们不就可以去切换那妞,控制去显示主界面了嘛!这里就要用到代理 Delegate 了( Ps: 你如果代码看的比较多,就会发现这个模式简直就是无处不再,太有用了), 触发按钮后通过代理,控制器类就会知道是哪一个按钮被点击了,很简单直接看代码:


#import <UIKit/UIKit.h>
#import "CustomTarbar.h"

@protocol CustomTarBarControllerDelegate;

@interface CustomTabBarController : UIViewController<CustomTabbarDelegate>
@property (nonatomic, strong) id<CustomTarBarControllerDelegate> delegate;
@property (nonatomic, strong) CustomTarbar *customTarbar;
@property (nonatomic, strong) NSMutableArray *viewControllers;
@property (nonatomic, strong) UIViewController *selectedViewController;
@property (nonatomic, strong) UIView *contentView;
@property (nonatomic) NSUInteger selectIndex;
@property (nonatomic) BOOL tabbarHidden;

- (void)setTabBarHidden:(BOOL)hidden animated:(BOOL)animated;

@end

@protocol CustomTarBarControllerDelegate <NSObject>
@optional
- (BOOL)tabBarController:(CustomTabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController;

- (void)tabBarController:(CustomTabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController;


@end
//
//  CustomTabBarController.m
//  CoolFrame
//
//  Created by silicon on 2017/7/25.
//  Copyright © 2017年 com.snailgames.coolframe. All rights reserved.
//

#import "CustomTabBarController.h"
#import <objc/runtime.h>

@interface CustomTabBarController ()

@end

@implementation CustomTabBarController
@synthesize delegate = _delegate;
@synthesize viewControllers = _viewControllers;
@synthesize selectIndex = _selectIndex;
@synthesize contentView = _contentView;
@synthesize customTarbar = _customTarbar;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.title = @"CoolFrame";
    [self.view addSubview:[self contentView]];
    [self.view addSubview:[self customTarbar]];

}

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [self setSelectIndex:[self selectIndex]];
    [[self customTarbar] setSelectedItem:[[self.customTarbar items] objectAtIndex:0]];
    [self setTabBarHidden:NO animated:NO];
}

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

#pragma -meathod

- (void)setViewControllers:(NSMutableArray *)viewControllers{
    if(viewControllers && [viewControllers isKindOfClass:[NSMutableArray class]]){
        _viewControllers = viewControllers;

        NSMutableArray *tabBarItems = [[NSMutableArray alloc] init];

        for (UIViewController *viewController in viewControllers) {
            CustomTabBarItem *tabBarItem = [[CustomTabBarItem alloc] init];
            [tabBarItem setTitle:viewController.title];
            [tabBarItems addObject:tabBarItem];
        }

        [[self customTarbar] setItems:tabBarItems];
    }
}

- (UIViewController *)selectedViewController{
    return [self.viewControllers objectAtIndex:self.selectIndex];
}

- (void)setSelectIndex:(NSUInteger)selectIndex{
    if(selectIndex > [self.viewControllers count]){
        return;
    }

    _selectIndex = selectIndex;
    if(_selectedViewController){
        [_selectedViewController willMoveToParentViewController:nil];
        [_selectedViewController.view removeFromSuperview];
        [_selectedViewController removeFromParentViewController];
    }

    [self setSelectedViewController:[self.viewControllers objectAtIndex:_selectIndex]];
    [self addChildViewController:self.selectedViewController];
    [[self selectedViewController].view setFrame:self.contentView.bounds];
    [self.contentView addSubview:self.selectedViewController.view];
    [self.selectedViewController didMoveToParentViewController:self];
}


- (UIView *)contentView{
    if(!_contentView){
        _contentView = [[UIView alloc] init];
        [_contentView setBackgroundColor:[UIColor whiteColor]];
        [_contentView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
    }

    return _contentView;
}

- (CustomTarbar *)customTarbar{
    if(!_customTarbar){
        _customTarbar = [[CustomTarbar alloc] init];
        [_customTarbar setBackgroundColor:[UIColor clearColor]];
        [_customTarbar setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
        _customTarbar.delegate = self;
    }

    return _customTarbar;
}

- (void)setTabBarHidden:(BOOL)hidden animated:(BOOL)animated{

    _tabbarHidden = hidden;
    CGSize viewSize = self.view.frame.size;
    CGFloat tabBarHeight = 49.0f;
    CGFloat tabBarY = viewSize.height;

    if(!hidden){
        tabBarY = viewSize.height - tabBarHeight;
        [[self customTarbar] setFrame:CGRectMake(0, tabBarY, viewSize.width, tabBarHeight)];
        [[self contentView] setFrame:CGRectMake(0, 0, viewSize.width, viewSize.height - tabBarHeight)];
    }

}

- (void)setTabbarHidden:(BOOL)tabbarHidden{
    [self setTabBarHidden:tabbarHidden animated:NO];
}

#pragma -CustomTabbarDelegate

- (BOOL)tabBar:(CustomTarbar *)tabBar shouldSelectItemAtIndex:(NSInteger)index{
    if (index > [self viewControllers].count) {
        return NO;
    }

    if([[self delegate] respondsToSelector:@selector(tabBarController:shouldSelectViewController:)]){
        if(![[self delegate] tabBarController:self shouldSelectViewController:[self viewControllers][index]]){
            return NO;
        }
    }

    if([self selectedViewController] == [self viewControllers][index]){
        if([[self selectedViewController] isKindOfClass:[UINavigationController class]]){
            UINavigationController *selectController = (UINavigationController *)[self selectedViewController];

            if([selectController topViewController] != [selectController viewControllers][0]){
                [selectController popToRootViewControllerAnimated:YES];
                return NO;
            }
        }

        return NO;
    }

    return YES;
}

- (void)tabBar:(CustomTarbar *)tabBar didSelectItemAtIndex:(NSInteger)index{
    if(index < 0 || index >= [self viewControllers].count){
        return;
    }

    [self setSelectIndex:index];
}

@end

到这里,还缺一个导航栏,缺了咋办,咱们来给他加上不就完事了嘛!首先定义一个类继承自 UINavigationBar ,这个类我用于控制导航栏的大小,再创建一个继承自UINavigationController 的类,控制我们的界面为竖屏,具体的代码如下:

#import "CustomNavBar.h"

@implementation CustomNavBar{
    CGSize _previousSize;
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

- (CGSize)sizeThatFits:(CGSize)size{
    size = [super sizeThatFits:size];
    if([UIApplication sharedApplication].statusBarHidden){
        size.height = 64;
    }

    return size;
}

- (void)layoutSubviews{
    [super layoutSubviews];

    if(CGSizeEqualToSize(self.bounds.size, _previousSize)){
        _previousSize = self.bounds.size;
        [self.layer removeAllAnimations];
        [self.layer.sublayers makeObjectsPerformSelector:@selector(removeAllAnimations)];
    }

}

@end
#import "CustomNavigationController.h"

@implementation CustomNavigationController

- (BOOL)shouldAutorotate{
    return YES;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    return UIInterfaceOrientationPortrait;
}

@end

最后,把该需要的资源文件都导入到工程目录中来,在我们的AppDelegate 中设置好,AppDelegate 代码如下:

#import "AppDelegate.h"

#import "CustomNavigationController.h"
#import "CustomNavBar.h"

#import "FirstViewController.h"
#import "SecondViewController.h"
#import "ThirdViewController.h"
#import "FouthViewController.h"

#define NQFONT(v) [UIFont fontWithName:@"HiraKakuProN-W3" size:v]
#define RGB(r, g, b)                        [UIColor colorWithRed:(r)/255.f green:(g)/255.f blue:(b)/255.f alpha:1.f]
@interface AppDelegate ()

@property (nonatomic, strong) FirstViewController *firstViewController;
@property (nonatomic, strong) SecondViewController *secondViewController;
@property (nonatomic, strong) ThirdViewController *thirdViewController;
@property (nonatomic, strong) FouthViewController *fouthViewController;
@property (nonatomic, strong) CustomTabBarController *tabBarController;

@property (nonatomic, strong) CustomNavigationController *navController;

@end


@implementation AppDelegate

- (void)setupViewControllers{
    if(!self.firstViewController){
        self.firstViewController = [[FirstViewController alloc] init];
    }

    if(!self.secondViewController){
        self.secondViewController = [[SecondViewController alloc] init];
    }

    if(!self.thirdViewController){
        self.thirdViewController = [[ThirdViewController alloc] init];
    }

    if(!self.fouthViewController){
        self.fouthViewController = [[FouthViewController alloc] init];
    }

    self.tabBarController = [[CustomTabBarController alloc] init];
    NSMutableArray *viewsArray = [[NSMutableArray alloc] initWithObjects:self.firstViewController,
                                  self.secondViewController,
                                  self.thirdViewController,
                                  self.fouthViewController, nil];

    [self.tabBarController setViewControllers:viewsArray];
    [self.tabBarController setSelectIndex:0];
    self.tabBarController.delegate = self;
    [self customizeTabBarForController:_tabBarController];

    if(!_navController){
        _navController  = [[CustomNavigationController new] initWithNavigationBarClass:[CustomNavBar class] toolbarClass:[UIToolbar class]];
        [_navController pushViewController:_tabBarController animated:NO];
    }
}

- (void)customizeTabBarForController:(CustomTabBarController *)tabBarController{
    UIImage *finishedImage = [UIImage imageNamed:@"tabbar_back_selected"];
    UIImage *unfinishedImage = [UIImage imageNamed:@"tabbar_back_normal"];
    NSArray *tabBarItemImages = @[@"latest",@"rank", @"contest", @"me"];
    NSArray *tabBarItemTitles = @[NSLocalizedString(@"新闻", nil),NSLocalizedString(@"直播", nil),NSLocalizedString(@"发现", nil), NSLocalizedString(@"我", nil)];
    NSInteger index = 0;
    for (CustomTabBarItem *item in [[tabBarController customTarbar] items])
    {
        [item setBackgroundSelectedImage:finishedImage withUnselectedImage:unfinishedImage];
        UIImage *selectedimage = [UIImage imageNamed:[tabBarItemImages objectAtIndex:index]];
        UIImage *unselectedimage = [UIImage imageNamed:[tabBarItemImages objectAtIndex:index]];
        [item setFinishedSelectedImage:selectedimage withFinishedUnselectedImage:unselectedimage];
        [item setTitle:[tabBarItemTitles objectAtIndex:index]];


        item.unselectedTitleAttributes= @{NSFontAttributeName: NQFONT(10), NSForegroundColorAttributeName: RGB(255, 255, 255),};

        item.selectedTitleAttributes = @{NSFontAttributeName: NQFONT(10), NSForegroundColorAttributeName: RGB(255, 255, 255),};


        index++;
    }
}


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [self.window setBackgroundColor:[UIColor whiteColor]];

    [self setupViewControllers];

    [self.window setRootViewController:_navController];
    [self.window makeKeyAndVisible];

    return YES;
}

到这里,我们的开发就算完成了,一个简单的 App 界面框架就诞生了,在接下来的几篇文章中,我会对其不断的完善,加上更多新的东西,让其成为一个真正意义上的 App。

好了。祝大家生活愉快。多多收获友谊和爱情。如果想获取更多的讯息,请扫描下方二维码关注我的微信公众号:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/shenjie12345678/article/details/76522223