前言

之前的一个项目,没有使用TabBar,而是选择用圆环作为用户点击的菜单,加上深蓝的冷色调,APP看着还蛮高大上,先看下效果图:

demo.gif

效果图分析

1.类似地球的是一张Image,其余的都是Button,每个button都是可以点击,点击回调至VC你可以处理一些事.

2.项目中的需求是旋转圆盘后自动会停止,停止时布局还是和最开始的一样(只不过可能不是原来的按钮),点击某个按钮,这个按钮就在最上方的中间处.

3.点击中间的按钮,圆盘能缩放,再次点击时显示.

实现

.h文件

这个文件定义一个回调block以及初始化view和传入数据的方法

#import

#import

typedef void(^clickSomeOne)(NSString *str);

@interface LWCustomCircleView : UIView

//在想要回传的界面中定义,block必须用copy来修饰

@property (nonatomic, copy) clickSomeOne clickButton;

- (id)initWithFrame:(CGRect)frame andImage:(UIImage *)image;

- (void)addSubviewWithSubView:(NSArray *)imageArray andTitle:(NSArray *)titleArray andSize:(CGSize)size andCenterImage:(UIImage *)centerImage;

@end

.m文件

定义的属性,注释的很清楚

@interface LWCustomCircleView()

/** 播放音效 */

@property (nonatomic, assign) SystemSoundID soundID;

/** 减速定时器 */

@property (nonatomic, strong) NSTimer *timer;

/** 子试图数量 */

@property (nonatomic, assign) CGFloat numOfSubView;

/** 圆形图 */

@property (nonatomic, strong) UIImageView *circleImage;

/** 减速定时器 */

@property (nonatomic, strong) UIImageView *arrowImage;

/** 子试图数组 */

@property (nonatomic, strong) NSMutableArray *subViewArray;

/** 按钮数组 */

@property (nonatomic, strong) NSMutableArray *buttonArray;

/** 第一触碰点 */

@property (nonatomic, assign) CGPoint beginPoint;

/** 第二触碰点 */

@property (nonatomic, assign) CGPoint movePoint;

/** 正在跑 */

@property (nonatomic, assign) BOOL isPlaying;

/** 滑动时间 */

@property (nonatomic, strong) NSDate *date;

/** 开始转动时间 */

@property (nonatomic, strong) NSDate *startTouchDate;

/** 减速计数 */

@property (nonatomic, assign) NSInteger decelerTime;

/** 子试图大小 */

@property (nonatomic, assign) CGSize subViewSize;

/** 滑动手势 */

@property (nonatomic, strong) UIPanGestureRecognizer *panGes;

/** 转动的角度 */

@property (nonatomic, assign) double mStartAngle;

/** 转动临界速度,超过此速度便是快速滑动,手指离开仍会转动 */

@property (nonatomic, assign) int mFlingableValue;

/** 半径 */

@property (nonatomic, assign) int mRadius;

/** 检测按下到抬起时旋转的角度 */

@property (nonatomic, assign) float mTmpAngle;

/** 顺时针转动的定时器 */

@property (nonatomic, strong) NSTimer *flowtime;

/**逆时针转动的定时器 */

@property (nonatomic, strong) NSTimer *reverseTime;

@property (nonatomic, assign) float anglePerSecond;

/** 转动速度 */

@property (nonatomic, assign) float speed;

@end

初始化视图和一些属性

- (id)initWithFrame:(CGRect)frame andImage:(UIImage *)image

{

if (self = [super initWithFrame:frame]) {

self.decelerTime = 0;

self.subViewArray = [[NSMutableArray alloc] init];

self.circleImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];

if (image == nil) {

self.circleImage.layer.cornerRadius = frame.size.width / 2;

}else {

self.circleImage.image = image;

self.circleImage.backgroundColor = [UIColor clearColor];

}

self.mRadius = frame.size.width / 2;

self.mStartAngle = M_PI_2 * 3;

self.mFlingableValue = 300;

self.isPlaying = false;

self.circleImage.userInteractionEnabled = YES;

[self addSubview:self.circleImage];

}

return self;

}

按钮的布局

给按钮添加图片和文字,中间的按钮只添加图片,添加滑动的手势和点击按钮时的重新布局

- (void)addSubviewWithSubView:(NSArray *)imageArray andTitle:(NSArray *)titleArray andSize:(CGSize)size andCenterImage:(UIImage *)centerImage

{

self.subViewSize = size;

self.numOfSubView = (CGFloat)titleArray.count;

self.buttonArray = [[NSMutableArray alloc] init];

for (NSInteger i = 0; i < self.numOfSubView; i++) {

UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(20*Width, 20*Width, size.width*Width, size.height*Height)];

[button setImage:imageArray[i] forState:UIControlStateNormal];

//设置image在button上的位置(上top,左left,下bottom,右right)这里可以写负值,对上写-5,那么image就象上移动5个像素

[button setTitle:titleArray[i] forState:UIControlStateNormal];

[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];

button.titleLabel.font = [UIFont systemFontOfSize:16*Width];

button.titleLabel.textAlignment = NSTextAlignmentCenter;

button.imageEdgeInsets = UIEdgeInsetsMake(8,8,8,button.titleLabel.bounds.size.width);

button.titleEdgeInsets = UIEdgeInsetsMake(70, -button.imageView.bounds.size.width-40, 0, 0);

[button addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];

button.tag = 100 + i;

[self.buttonArray addObject:button];

[self.subViewArray addObject:button];

[self.circleImage addSubview:button];

}

//按钮布局

[self layoutButton];

//中间按钮

UIButton *centerBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width/3.0, self.frame.size.height/3.0)];

centerBtn.tag = 100 + self.numOfSubView + 1;

centerBtn.layer.cornerRadius = self.frame.size.width / 6.0;

[centerBtn setImage:centerImage forState:UIControlStateNormal];

centerBtn.center = CGPointMake(self.frame.size.width/2.0, self.frame.size.height / 2.0);

[centerBtn addTarget:self action:@selector(clickBtnCenter:) forControlEvents:UIControlEventTouchUpInside];

[self.subViewArray addObject:centerBtn];

[self.circleImage addSubview:centerBtn];

//转动手势

self.panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(zhuanPgr:)];

[self.circleImage addGestureRecognizer:self.panGes];

//加点击效果

for (NSInteger i=0; i

UIButton *button= self.subViewArray[i];

[button addTarget:self action:@selector(subViewOut:) forControlEvents:UIControlEventTouchUpInside];

}

}

按钮的布局

按钮分布在圆环上,这里用到正弦和余弦函数

//按钮布局

- (void)layoutButton

{

/**

M_PI pi 3.14159265358979323846

M_PI_2 pi/2 1.57079632679489661923

M_PI_4 pi/4 0.785398163397448309616

*/

/**

sin((i/self.numOfSubView) * M_PI * 2 + self.mStartAngle):布局滑动时按钮均匀分布在圆的各个位置

(self.frame.size.width/2 - self.subViewSize.width/2 - 20):让按钮布局在圆环间

*/

for (NSInteger i = 0; i < self.numOfSubView; i++) {

CGFloat yy = 195 + sin((i/self.numOfSubView) * M_PI * 2 + self.mStartAngle) * (self.frame.size.width/2 - self.subViewSize.width/2 - 30);

CGFloat xx = 195 + cos((i/self.numOfSubView) * M_PI * 2 + self.mStartAngle) * (self.frame.size.width/2 - self.subViewSize.width/2 - 30);

UIButton *button = [self.buttonArray objectAtIndex:i];

button.center = CGPointMake(xx, yy);

}

}

滑动手势的处理

代码中的注释很详细

-(void)zhuanPgr:(UIPanGestureRecognizer *)pgr

{

if (pgr.state == UIGestureRecognizerStateBegan) {

self.mTmpAngle = 0;

self.beginPoint = [pgr locationInView:self];

self.startTouchDate = [NSDate date];

}else if (pgr.state == UIGestureRecognizerStateChanged) {

float StartAngleLast = self.mStartAngle;

self.movePoint = [pgr locationInView:self];

float start = [self getAngle:self.beginPoint];

float end = [self getAngle:self.movePoint];

if ([self getQuadrant:self.movePoint] == 1 || [self getQuadrant:self.movePoint] == 4) {

//一、四象限

self.mStartAngle += end - start;

self.mTmpAngle += end - start;

}else {

//二三象限

self.mStartAngle += start - end;

self.mTmpAngle += start - end;

}

[self layoutButton];

self.beginPoint = self.movePoint;

self.speed = self.mStartAngle - StartAngleLast;

NSTimeInterval time = [[NSDate date] timeIntervalSinceDate:self.startTouchDate];

self.anglePerSecond = self.mTmpAngle * 50 / time;

}else if (pgr.state == UIGestureRecognizerStateEnded) {

//计算每秒转动的角度

NSTimeInterval time = [[NSDate date] timeIntervalSinceDate:self.startTouchDate];

self.anglePerSecond = self.mTmpAngle * 50 / time;

if (self.anglePerSecond > 0) {

//求绝对值的函数,顺时针转动

if (fabs(self.anglePerSecond) > self.mFlingableValue && !self.isPlaying) {

self.isPlaying = true;

self.flowtime = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(flowAction) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:self.flowtime forMode:NSRunLoopCommonModes];

}

}else {

//逆时针转动

if (-fabsf(self.anglePerSecond) < -self.mFlingableValue && !self.isPlaying) {

self.isPlaying = true;

self.reverseTime = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(reverseAction) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:self.reverseTime forMode:NSRunLoopCommonModes];

}

}

if (self.isPlaying == false){

if (self.mStartAngle >= 0){

//fmod是取两个数相除的余数

if (fmod(self.mStartAngle, M_PI*2) > M_PI_2*2.32+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2) <= M_PI_2*3+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*3;

[self layoutButton];

self.clickButton(@"100");

}

if (fmod(self.mStartAngle, M_PI*2) > M_PI_2*1.68+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2) <= M_PI_2*2.32+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*2.32;

[self layoutButton];

self.clickButton(@"101");

}

if (fmod(self.mStartAngle, M_PI*2) > M_PI_2*1+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)<=M_PI_2*1.68+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*1.68;

[self layoutButton];

self.clickButton(@"102");

}

if (fmod(self.mStartAngle, M_PI*2) > M_PI_2*0.32+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)<=M_PI_2*1+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*1;

[self layoutButton];

self.clickButton(@"103");

}

if (fmod(self.mStartAngle, M_PI*2) > 0 && fmod(self.mStartAngle, M_PI*2) <= M_PI_2*0.32+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*0.32;

[self layoutButton];

self.clickButton(@"104");

}

if (fmod(self.mStartAngle, M_PI*2)-M_PI*2 <= 0 && fmod(self.mStartAngle, M_PI*2)-M_PI*2 >= -M_PI_2*0.32*2) {

// mStartAngle = M_PI_2*3.66;

self.mStartAngle = -M_PI_2*0.32;

[self layoutButton];

self.clickButton(@"105");

}

}else {

if (fmod(self.mStartAngle, M_PI*2)+M_PI*2 > M_PI_2*2.32+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)+M_PI*2<=M_PI_2*3+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*3;

[self layoutButton];

self.clickButton(@"100");

}

if (fmod(self.mStartAngle, M_PI*2)+M_PI*2 > M_PI_2*1.68+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)+M_PI*2<=M_PI_2*2.32+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*2.32;

[self layoutButton];

self.clickButton(@"101");

}

if (fmod(self.mStartAngle, M_PI*2)+M_PI*2 > M_PI_2*1+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)+M_PI*2<=M_PI_2*1.68+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*1.68;

[self layoutButton];

self.clickButton(@"102");

}

if (fmod(self.mStartAngle, M_PI*2)+M_PI*2 > M_PI_2*0.32+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)+M_PI*2<=M_PI_2*1+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*1;

[self layoutButton];

self.clickButton(@"103");

}

if (fmod(self.mStartAngle, M_PI*2)+M_PI*2 > 0+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)+M_PI*2<=M_PI_2*0.32+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*0.32;

[self layoutButton];

self.clickButton(@"104");

}

if (fmod(self.mStartAngle, M_PI*2) <= 0 && fmod(self.mStartAngle, M_PI*2) >= -M_PI_2*0.32*2) {

// mStartAngle = M_PI_2*3.66;

self.mStartAngle = -M_PI_2*0.32;

[self layoutButton];

self.clickButton(@"105");

}

}

}

}

}

//获取当前点弧度

/**

hypot:计算直角三角形的斜边长

*/

-(float)getAngle:(CGPoint)point {

double x = point.x - self.mRadius;

double y = point.y - self.mRadius;

return (float) (asin(y / hypot(x, y)));

}

/** 根据当前位置计算象限 */

-(int) getQuadrant:(CGPoint) point {

int tmpX = (int) (point.x - self.mRadius);

int tmpY = (int) (point.y - self.mRadius);

if (tmpX >= 0) {

return tmpY >= 0 ? 1 : 4;

} else {

return tmpY >= 0 ? 2 : 3;

}

}

顺时针和逆时针转动的定时器处理

速度减为零时,按钮重新布局,并销毁定时器

- (void)flowAction

{

if (self.speed < 0.1) {

[UIView animateWithDuration:2 animations:^{

} completion:^(BOOL finished) {

}];

self.isPlaying = false;

[self.flowtime invalidate];

self.flowtime = nil;

//停止转动时,布局好按钮位置,不需要这样的效果可注释

if (fmod(self.mStartAngle, M_PI*2) > M_PI_2*2.32+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2) <= M_PI_2*3+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*3;

[self layoutButton];

self.clickButton(@"100");

}

if (fmod(self.mStartAngle, M_PI*2) > M_PI_2*1.68+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2) <= M_PI_2*2.32+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*2.32;

[self layoutButton];

self.clickButton(@"101");

}

if (fmod(self.mStartAngle, M_PI*2) > M_PI_2*1+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2) <= M_PI_2*1.68+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*1.68;

[self layoutButton];

self.clickButton(@"102");

}

if (fmod(self.mStartAngle, M_PI*2) > M_PI_2*0.32+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2) <= M_PI_2*1+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*1;

[self layoutButton];

self.clickButton(@"103");

}

if (fmod(self.mStartAngle, M_PI*2) > 0 && fmod(self.mStartAngle, M_PI*2) <= M_PI_2*0.32+M_PI_2*0.32) {

self.mStartAngle = M_PI_2*0.32;

[self layoutButton];

self.clickButton(@"104");

}

if (fmod(self.mStartAngle, M_PI*2)-M_PI*2 <= 0 && fmod(self.mStartAngle, M_PI*2)-M_PI*2 >= -M_PI_2*0.32*2) {

// mStartAngle = M_PI_2*3.66;

self.mStartAngle = -M_PI_2*0.32;

[self layoutButton];

self.clickButton(@"105");

}

return;

}

// 不断改变mStartAngle,让其滚动,/30为了避免滚动太快

self.mStartAngle += self.speed ;

self.speed = self.speed/1.1;

// 逐渐减小这个值

// anglePerSecond /= 1.1;

[self layoutButton];

}

- (void)reverseAction

{

if (self.speed > -0.1) {

[UIView animateWithDuration:2 animations:^{

} completion:^(BOOL finished) {

}];

self.isPlaying = false;

[self.reverseTime invalidate];

self.reverseTime = nil;

//停止转动时,布局好按钮位置,不需要这样的效果可注释

if ((fmod(self.mStartAngle, M_PI*2)+M_PI*2 > M_PI_2*2.32+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)+M_PI*2 <= M_PI_2*3+M_PI_2*0.32) || (fmod(self.mStartAngle, M_PI*2)>M_PI_2*2.32+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)<=M_PI_2*3+M_PI_2*0.32)) {

self.mStartAngle = M_PI_2*3;

[self layoutButton];

self.clickButton(@"100");

}

if ((fmod(self.mStartAngle, M_PI*2)+M_PI*2>M_PI_2*1.68+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)+M_PI*2<=M_PI_2*2.32+M_PI_2*0.32)||(fmod(self.mStartAngle, M_PI*2)>M_PI_2*1.68+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)<=M_PI_2*2.32+M_PI_2*0.32)) {

self.mStartAngle = M_PI_2*2.32;

[self layoutButton];

self.clickButton(@"101");

}

if ((fmod(self.mStartAngle, M_PI*2)+M_PI*2>M_PI_2*1+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)+M_PI*2<=M_PI_2*1.68+M_PI_2*0.32)||(fmod(self.mStartAngle, M_PI*2)>M_PI_2*1+M_PI_2*0.32&&fmod(self.mStartAngle, M_PI*2)<=M_PI_2*1.68+M_PI_2*0.32)) {

self.mStartAngle = M_PI_2*1.68;

[self layoutButton];

self.clickButton(@"102");

}

if ((fmod(self.mStartAngle, M_PI*2)+M_PI*2 > M_PI_2*0.32+M_PI_2*0.32 && fmod(self.mStartAngle, M_PI*2)+M_PI*2 <= M_PI_2*1+M_PI_2*0.32) || (fmod(self.mStartAngle, M_PI*2) > M_PI_2*0.32+M_PI_2*0.32&&fmod(self.mStartAngle, M_PI*2) <= M_PI_2*1+M_PI_2*0.32)) {

self.mStartAngle = M_PI_2*1;

[self layoutButton];

self.clickButton(@"103");

}

if ((fmod(self.mStartAngle, M_PI*2)+M_PI*2>0 && fmod(self.mStartAngle, M_PI*2)+M_PI*2 <= M_PI_2*0.32+M_PI_2*0.32)||(fmod(self.mStartAngle, M_PI*2)>0&&fmod(self.mStartAngle, M_PI*2)<=M_PI_2*0.32+M_PI_2*0.32)) {

self.mStartAngle = M_PI_2*0.32;

[self layoutButton];

self.clickButton(@"104");

}

if (fmod(self.mStartAngle, M_PI*2)<=0 && fmod(self.mStartAngle, M_PI*2) >= -M_PI_2*0.32*2) {

// mStartAngle = M_PI_2*3.66;

self.mStartAngle = -M_PI_2*0.32;

[self layoutButton];

self.clickButton(@"105");

}

return;

}

self.mStartAngle += self.speed;

self.speed = self.speed/1.1;

[self layoutButton];

}

ios 圆形旋转菜单_iOS 圆环菜单相关推荐

  1. ios 圆形旋转菜单_iOS高级动画:圆形树展开收起动画

    转自:标哥的技术博客,作者:黄仪标(微博) 前段时间帮某某做了一个动画效果,今天分享给大家.关于动画的基础知识,这里不会细说,如果您还没有核心动画的基础知识,请先阅读相关文章,了解核心动画如何使用,然 ...

  2. ios 圆形旋转菜单_iOS实现滑动弧形菜单的思路与方法

    前言 最近公司的项目中需要用到弧形菜单,起初自定义UICollectionView的layout,但实现出的效果并不符合项目中要求按钮始终垂直于界面.界面始终保持几个按钮等一系列需求(是我水平不够), ...

  3. ios 圆形旋转菜单_iOS 屏幕强制旋转 (模态、Push、导航栏、状态栏)

    界面旋转准备 在AppDelegate.h中添加属性 //是否旋转 @property (nonatomic, assign) BOOL isRotation; 在AppDelegate.m中添加方法 ...

  4. ios 横向滚轮效果_ios横向菜单+页面滑动

    ios横向菜单+页面滑动 查看次数:9122 下载次数:992 上传时间:2016-06-28 大小:11 B Demo: https://github.com/Super-lying/LyScrol ...

  5. android圆形旋转菜单,而对于移动转换功能支持

    LZ该公司最近接手一个项目,需要写一个圆形旋转菜单,和菜单之间的移动换位支持,我本来以为这样的demo如若互联网是非常.想想你妈妈也帮不了我,空旋转,但它不能改变位置,所以LZ我们只能靠自己摸索. 最 ...

  6. Android 圆形旋转菜单

    我的视频课程:<FFmpeg打造Android万能音频播放器> 最近帮朋友做了一个动画菜单,感觉有一定的实用价值,就在此给大家分享一下,先看看效果:源码下载地址在末尾 实现思路: 从图中可 ...

  7. html旋转的环形菜单,前端开发圆形旋转导航菜单教程

    /p> 前端开发商城页面:圆形旋转导航菜单 html, body { padding: 0; margin: 0; } 圆形菜单[最多容纳8个最大正方形菜单块, 若需容纳更多的菜单块,则需要缩小 ...

  8. 张高兴的 Xamarin.Forms 开发笔记:为 Android 与 iOS 引入 UWP 风格的汉堡菜单 ( MasterDetailPage )...

    所谓 UWP 样式的汉堡菜单,我曾在"张高兴的 UWP 开发笔记:汉堡菜单进阶"里说过,也就是使用 Segoe MDL2 Assets 字体作为左侧 Icon,并且左侧使用填充颜色 ...

  9. Android仿QQ ios dialog,仿QQ退出向上菜单

    Android仿QQ ios dialog,仿QQ退出向上菜单 EasyDialog两种模式 仿QQ退出向上菜单,自定义向上菜单              github地址:https://githu ...

最新文章

  1. html2canvas在Vue项目踩坑-生成图片偏移不完整
  2. python tuple类型和list_Python 04_List 和 Tuple 类型
  3. C#中Lambda表达式动态拼接生成工具类
  4. LINUX创建桌面运行快捷方式
  5. 视频时帧率达到15,人眼就感觉是连续的
  6. 京东量化平台宣告下线,其他平台该何去何从?
  7. c语言关键字及其含义,C语言关键字解析
  8. 因子分析累计贡献率_数据分析之因子分析
  9. 树莓派linux负载均衡集群,在树莓派2上Nginx并发1W到底有多难
  10. 网络精英赛模拟练习(8)
  11. java短信验证码功能发送的验证码如何校验_Java实现短信发送验证码功能
  12. 深入理解Flash Player的安全域(Security Domains)
  13. Docker 的新变化你知道多少?
  14. Apache Velocity 模板语言 特殊字符${ $!{ 原样输出问题 转义符 # ! 无效
  15. 苹果加快自研脚步,被国产厂商逼的?
  16. Android Studio 使用记录
  17. web前端的网页优化
  18. Python脚本抢购茅台,一键式傻瓜教程,不会python 也能用
  19. 【LaTeX符号】条件独立与不独立符号
  20. cocos creator移动事件和 opacity

热门文章

  1. 用PS制作APP的界面图片
  2. G - IP地址转换
  3. Python 正则表达式
  4. 压缩工具gzip,bzip2,xz,zip,tar
  5. 手机壳释放致癌物质“苯”吗?专家:确实会
  6. API HTTP 请求调试:Postman
  7. 测试sql语句执行时间
  8. 电子邮件的故事:令人吃惊的预测
  9. 升级SharePoint场的时候, 运行Configuration Wizard需要有什么顺序么?
  10. 如何解决传输模式解决FTP连接问题