ios 圆形旋转菜单_iOS 圆环菜单
前言
之前的一个项目,没有使用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 圆环菜单相关推荐
- ios 圆形旋转菜单_iOS高级动画:圆形树展开收起动画
转自:标哥的技术博客,作者:黄仪标(微博) 前段时间帮某某做了一个动画效果,今天分享给大家.关于动画的基础知识,这里不会细说,如果您还没有核心动画的基础知识,请先阅读相关文章,了解核心动画如何使用,然 ...
- ios 圆形旋转菜单_iOS实现滑动弧形菜单的思路与方法
前言 最近公司的项目中需要用到弧形菜单,起初自定义UICollectionView的layout,但实现出的效果并不符合项目中要求按钮始终垂直于界面.界面始终保持几个按钮等一系列需求(是我水平不够), ...
- ios 圆形旋转菜单_iOS 屏幕强制旋转 (模态、Push、导航栏、状态栏)
界面旋转准备 在AppDelegate.h中添加属性 //是否旋转 @property (nonatomic, assign) BOOL isRotation; 在AppDelegate.m中添加方法 ...
- ios 横向滚轮效果_ios横向菜单+页面滑动
ios横向菜单+页面滑动 查看次数:9122 下载次数:992 上传时间:2016-06-28 大小:11 B Demo: https://github.com/Super-lying/LyScrol ...
- android圆形旋转菜单,而对于移动转换功能支持
LZ该公司最近接手一个项目,需要写一个圆形旋转菜单,和菜单之间的移动换位支持,我本来以为这样的demo如若互联网是非常.想想你妈妈也帮不了我,空旋转,但它不能改变位置,所以LZ我们只能靠自己摸索. 最 ...
- Android 圆形旋转菜单
我的视频课程:<FFmpeg打造Android万能音频播放器> 最近帮朋友做了一个动画菜单,感觉有一定的实用价值,就在此给大家分享一下,先看看效果:源码下载地址在末尾 实现思路: 从图中可 ...
- html旋转的环形菜单,前端开发圆形旋转导航菜单教程
/p> 前端开发商城页面:圆形旋转导航菜单 html, body { padding: 0; margin: 0; } 圆形菜单[最多容纳8个最大正方形菜单块, 若需容纳更多的菜单块,则需要缩小 ...
- 张高兴的 Xamarin.Forms 开发笔记:为 Android 与 iOS 引入 UWP 风格的汉堡菜单 ( MasterDetailPage )...
所谓 UWP 样式的汉堡菜单,我曾在"张高兴的 UWP 开发笔记:汉堡菜单进阶"里说过,也就是使用 Segoe MDL2 Assets 字体作为左侧 Icon,并且左侧使用填充颜色 ...
- Android仿QQ ios dialog,仿QQ退出向上菜单
Android仿QQ ios dialog,仿QQ退出向上菜单 EasyDialog两种模式 仿QQ退出向上菜单,自定义向上菜单 github地址:https://githu ...
最新文章
- html2canvas在Vue项目踩坑-生成图片偏移不完整
- python tuple类型和list_Python 04_List 和 Tuple 类型
- C#中Lambda表达式动态拼接生成工具类
- LINUX创建桌面运行快捷方式
- 视频时帧率达到15,人眼就感觉是连续的
- 京东量化平台宣告下线,其他平台该何去何从?
- c语言关键字及其含义,C语言关键字解析
- 因子分析累计贡献率_数据分析之因子分析
- 树莓派linux负载均衡集群,在树莓派2上Nginx并发1W到底有多难
- 网络精英赛模拟练习(8)
- java短信验证码功能发送的验证码如何校验_Java实现短信发送验证码功能
- 深入理解Flash Player的安全域(Security Domains)
- Docker 的新变化你知道多少?
- Apache Velocity 模板语言 特殊字符${ $!{ 原样输出问题 转义符 # ! 无效
- 苹果加快自研脚步,被国产厂商逼的?
- Android Studio 使用记录
- web前端的网页优化
- Python脚本抢购茅台,一键式傻瓜教程,不会python 也能用
- 【LaTeX符号】条件独立与不独立符号
- cocos creator移动事件和 opacity