iOS 제스처 슬라이딩 잠 금 해제 기능 분석 실현
21714 단어 iOS손짓자 물 쇠 를 풀다
일상생활 에서 우 리 는 제스처 가 미 끄 러 지 는 것 을 자주 만 날 수 있 습 니 다.즉,구 궁 격 입 니 다.이미 나타 난 지 오래 되 었 습 니 다.애플 의 지문 잠 금 해제 의 발전 에 따라 제스처 잠 금 해제 도 있 지만 지문 잠 금 해제 보다 편리 하지 않 기 때문에 사용 하 는 것 도 적 습 니 다.그러나 대부분 앱 에서 이 두 가지 방식 은 모두 공존 합 니 다.예 를 들 어 qq,위 챗,알 리 페 이 등 입 니 다.최근 프로젝트 에서 도 이런 수요 가 있 었 다.방금 완성 한 시간 을 틈 타 그 당시 의 생각 을 기록 했다.어떤 부분 은 제대로 이해 하지 못 했 을 수도 있 고 정 리 를 많이 해 야 한다.잡담 을 적 게 하고 중심 을 봐 야 한다.
기능 설명 은 그림 과 같다.대충 생각 을 말 해 보 자.이 기능 은 암호 에 해당 하 는 것 으로 양쪽 의 일치 에 사용 된다.교사 단 은 경로 생 성 비밀 번 호 를 설정 하고 현지 에 저장 하 며 학생 단 은 미끄럼 입력 으로 검증 한다.그리고 여러 가지 상황 에 따라 상부 의 label 이 여러 가지 힌트 정 보 를 주 었 습 니 다.여 기 는 원시 적 이 고 허름 한 demo 일 뿐 우리 가 가장 흔히 볼 수 있 는 기능 을 실 현 했 기 때문에 그 중의 정신 을 이해 하 는 데 중심 을 두 었 습 니 다.하하 하.
기능 모듈 분석
GIF 에 따 르 면 이 기능 을 몇 가지 부분 으로 간단하게 나 눌 수 있 습 니 다.첫 번 째 는 첫 번 째 페이지 입 니 다.ViewController 입 니 다.첫 번 째 페이지 에는 두 개의 Controller 가 있 는데 그것 이 바로 StudViewController 와 TeacViewController 가 서로 다른 기능 의 운반 체 로 나 눌 수 있 습 니 다.StudView Controller 에 서 는 세 부분 상하 status Label Gesture LockView clearbtn 으로 나 뉘 는데 그 중에서 Gesture LockView 는 제스처 잠 금 해제 인터페이스 이다.TeacviewController 에서 도 세 부분 으로 나 뉘 는데 status Label Gesture LockView BottomView 아래 의 bottomView 는 button resetBtn 리 셋 단추 와 sureBtn 확인 단추 로 나 뉜 다.대체적인 구 조 를 말 하고 다음 부분 으로 나 누 어 모든 기능 의 실현 방향 을 말 해 보 자.
해체 분석
먼저 Gesture LockView 라 는 view 컨트롤 을 말씀 드 리 겠 습 니 다.
우선.h 파일 에서
두 개의 매 거 진 을 정의 합 니 다.각각 양 끝 의 서로 다른 유형 을 정의 하 는 데 사 용 됩 니 다.stu 단 은 ResultKind Type 으로 그림 의 제스처 결 과 를 이 네 가지 로 분류 합 니 다.다음은 모두 사용 되 고 용 도 를 설명 합 니 다.teac 엔 드 는 TeacKind Type 으로 두 가지 유형 으로 나 뉜 다.
// / / 4
typedef NS_ENUM(NSUInteger, ResultKindType) {
ResultKindTypeTrue,
ResultKindTypeFalse,
ResultKindTypeNoEnough,
ResultKindTypeClear
};
typedef NS_ENUM(NSUInteger, TeacKindType) {
TeacKindTypeNoEnough,
TeacKindTypeTrue
};
프로 토 콜:제스처 가 바 뀌 었 을 때 전 달 된 전환 암 호 를 감청 하 는 데 사 용 됩 니 다.(이 암 호 는 button 의 tag 값 으로 표 시 됩 니 다.)제스처 가 바 뀌 었 기 때문에 NSMutableString 으로 밖으로 전 달 됩 니 다.
@protocol GestureLockDelegate <NSObject>
- (void)gestureLockView:(GestureLockView *)lockView drawRectFinished:(NSMutableString *)gesturePassword;
@end
속성:방법:
- (void)clearLockView;//
- (void)checkPwdResult:(ResultKindType)resultType;//
- (void)checkTeacResult:(TeacKindType)resultType;//
.m 파일 에서(구체 적 으로 만 들 고 응용 하 는 방법)설명 변 수 는 아래 에서 사용 할 수 있 습 니 다:
@interface GestureLockView ()
@property (strong, nonatomic) NSMutableArray *selectBtns;//
@property (nonatomic, strong) NSMutableArray *errorBtns;//
@property(nonatomic, assign)BOOL finished;//
@property (nonatomic, assign) CGPoint currentPoint;//
@property (nonatomic, assign) ResultKindType resultType;//
@property (nonatomic, assign) TeacKindType teacResultType;//
@end
게 으 른 로드 초기 화 배열
- (NSMutableArray *)selectBtns {
if (!_selectBtns) {
_selectBtns = [NSMutableArray array];
}
return _selectBtns;
}
- (NSMutableArray *)errorBtns {
if (!_errorBtns) {
_errorBtns = [NSMutableArray array];
}
return _errorBtns;
}
하위 보기 초기 화:여기에서 9 개의 단 추 를 만 들 고 self 에 추가 하 며,self 에 UIPanGesture Recognizer*pan 제스처 를 추가 합 니 다.
- (void)initSubviews {
self.backgroundColor = [UIColor clearColor];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self addGestureRecognizer:pan];
// 9
for (NSInteger i = 0; i < 9; i++) {
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.userInteractionEnabled = NO;
[btn setImage:[UIImage imageNamed:@"sign_img_circle_n"] forState:UIControlStateNormal];
[btn setImage:[UIImage imageNamed:@"sign_img_circle_s"] forState:UIControlStateSelected];
btn.tag = i+1;
[self addSubview:btn];
}
}
인터페이스 레이아웃:
CGFloat minWidth = MIN(self.bounds.size.height, self.bounds.size.width);
CGFloat boundsWidth = self.bounds.size.width;
CGFloat margin = (minWidth - cols * w) / (cols + 1);//
CGFloat xMargin = (boundsWidth-2*margin-3*w)/2;
여기 서 이 부분 은 서로 다른 기종 에 적합 합 니 다.이 컨트롤 은 height
- (void)layoutSubviews {
[super layoutSubviews];
NSUInteger count = self.subviews.count;
int cols = 3;//
CGFloat x = 0,y = 0,w = 0,h = 0;
if (SCREEN_WIDTH == 320) {
w = 50;
h = 50;
} else {
w = 60;
h = 60;
}
CGFloat minWidth = MIN(self.bounds.size.height, self.bounds.size.width);
CGFloat boundsWidth = self.bounds.size.width;
CGFloat margin = (minWidth - cols * w) / (cols + 1);//
CGFloat xMargin = (boundsWidth-2*margin-3*w)/2;
CGFloat col = 0;
CGFloat row = 0;
for (int i = 0; i < count; i++) {
col = i % cols;
row = i / cols;
if (i == 0 || i == 3 || i == 6) {
x = xMargin;
} else if (i == 1 || i == 4 || i == 7) {
x = xMargin + w + margin;
} else {
x = xMargin + 2 * (margin+w);
}
y = (w+margin)*row;
UIButton *btn = self.subviews[i];
btn.frame = CGRectMake(x, y, w, h);
}
}
제스처 에이전트 방법:제스처 에이전트 방법 에서 제스처 가 미 끄 러 지 는 위치의 변 화 를 감청 합 니 다.pan.state=UIGesture Recognizer StateBegan 이 미 끄 러 지기 시 작 했 을 때 오류 상 태 를 보 여 주 는 button 을 일반 초기 상태 로 바 꾸 고 self.errorBtns 배열 을 지 웁 니 다.장currentPoint = [pan locationInView:self];미 끄 러 질 때 현재 위치 point 를 검사 합 니 다.그 어 진 위치 가 button 범위 에 포함 되 어 있 으 면 button.selected==NO 라면 button.selected=YES;/선택 하고 button 을 self.selectBtns 배열 에 추가 합 니 다[self.selectBtns addObject:button];[self setNeedsDisplay]호출;방법 을 다시 그립 니 다.setNeedsDisplay 방법 시스템 을 호출 하면 draw React 방법 으로 인터페이스의 재 구성 을 자동 으로 호출 합 니 다.마지막 으로 손가락 을 놓 을 지 여부//감청 손가락 을 놓 을 지 여부 if(pan.state==UIGesture Recognizer StateEnded){self.finished=YES;}self.finished=YES;
#pragma mark
- (void)pan:(UIPanGestureRecognizer *)pan {
if (pan.state == UIGestureRecognizerStateBegan) {
for (UIButton *btn in _errorBtns) {
[btn setImage:[UIImage imageNamed:@"sign_img_circle_n"] forState:UIControlStateNormal];
[btn setImage:[UIImage imageNamed:@"sign_img_circle_s"] forState:UIControlStateSelected];
}
[self.errorBtns removeAllObjects];
}
_currentPoint = [pan locationInView:self];
for (UIButton *button in self.subviews) {
if (CGRectContainsPoint(button.frame, _currentPoint)) {
if (button.selected == NO) {
//
button.selected = YES;//
[self.selectBtns addObject:button];
} else {
}
}
}
//
[self setNeedsDisplay];
//
if (pan.state == UIGestureRecognizerStateEnded) {
self.finished = YES;
}
}
설정 한 제스처 암호 전달 방법
//
- (NSMutableString *)transferGestureResult {
//
NSMutableString *result = [NSMutableString string];
for (UIButton *btn in self.selectBtns) {
[result appendFormat:@"%ld", btn.tag - 1];
}
return result;
}
양쪽 의 외부 작업 이 내부 상태 에 대한 변경:
case ResultKindTypeFalse:
_errorBtns = [NSMutableArray arrayWithArray:self.selectBtns];
break;
그림%1 개의 캡 션 을 편 집 했 습 니 다.errorBtns 에서 오류 단 추 를 넣 은 그룹
case ResultKindTypeClear:
{
[[UIColor clearColor] set];
for (int i = 0; i < self.errorBtns.count; i++) {
UIButton *btn = [self.errorBtns objectAtIndex:i];
[btn setImage:[UIImage imageNamed:@"sign_img_circle_n"] forState:UIControlStateNormal];
}
[self.errorBtns removeAllObjects];
}
break;
외부 에서 상태 가'제거'로 바 뀌 었 을 때 경 로 를 투명 하 게 설정 하고 errorBtns 배열 의 button 배경 색 상 태 를 바 꾸 고 errorBtns 를 비 웁 니 다.여기 서 왜 이런 변 화 를 합 니까?이것 은 학생 측 에서 제거 작업 을 할 때 제스처 의 상태 가 finish 이 고 이것 은 후 에이전트 방법 이 끝 났 기 때 문 입 니 다.또한 clearLockView 방법 을 호출 할 때 selectBtns 배열 을 비 웠 기 때문에 setNeeds Display 가 호출 되 었 습 니 다.drawReact 가 다시 그 릴 때 if()가 감지 되 었 습 니 다.selectBtns.count == 0) return;더 이상 진행 하지 않 겠 습 니 다.
//
- (void)checkPwdResult:(ResultKindType)resultType {
self.resultType = resultType;
switch (resultType) {
case ResultKindTypeFalse:
_errorBtns = [NSMutableArray arrayWithArray:self.selectBtns];
break;
case ResultKindTypeTrue:
break;
case ResultKindTypeNoEnough:
break;
case ResultKindTypeClear:
{
[[UIColor clearColor] set];
for (int i = 0; i < self.errorBtns.count; i++) {
UIButton *btn = [self.errorBtns objectAtIndex:i];
[btn setImage:[UIImage imageNamed:@"sign_img_circle_n"] forState:UIControlStateNormal];
}
[self.errorBtns removeAllObjects];
}
break;
default:
break;
}
[self clearLockView];
}
//
- (void)checkTeacResult:(TeacKindType)resultType {
self.teacResultType = resultType;
switch (resultType) {
case TeacKindTypeTrue:
break;
case TeacKindTypeNoEnough:{
[self clearLockView];
}
break;
default:
break;
}
}
제거 방법:self.finished=NO;프 록 시 를 통 해 값 을 외부 로 전달 하고 외부 에서 이 값 을 검사 한 결과 내용 의 resultType 을 바 꾸 었 다 면 이 때 는 draw React 방법 에 있 었 고 self.finished 방법 을 마 쳤 기 때 문 입 니 다.여기 서 NO 로 설정 한 것 은 다음 에 그 려 진 finished 상 태 를 바 꾸 기 위해 서 입 니 다.눈 에 띄 지 않 지만 썼 습 니 다.
- (void)clearLockView {
self.finished = NO;
//
for (UIButton *btn in self.selectBtns) {
//
btn.selected = NO;
}
[self.selectBtns removeAllObjects];
//
[self setNeedsDisplay];
}
베 어 셀 곡선 을 이용 하여 경 로 를 그립 니 다.해당 상태 에 따라 경로 색상,단추 색상 을 변경 합 니 다.시스템 이 이 방법 을 호출 할 때 다시 그립 니 다.다시 그립 니 다.self.selectBtns 배열 에서 선택 한 button 을 꺼 냅 니 다.button 이 첫 번 째 일 때 bezierPath 의 출발점[path moveToPoint:btn.center]으로 설정 합 니 다.나머지 단 추 는 경로[path addLineToPoint:btn.center]를 그립 니 다.여기 서 손가락 을 풀 었 는 지 여 부 를 판단 합 니 다.이 판단 에 서 는 논리 적 판단 이 많 습 니 다.대충 훑 어보 세 요.self.finished==YES 일 때 만 든 비밀 번 호 를 이전 성명 의 대 리 를 이용 하여 외부 에 전달 하여 검사 합 니 다.외부 에서 되 돌아 오 는 동작 상태 에 따라 self.isTeac 가 되 돌아 오 는 결과 상태 에 따라 판단 합 니 다.
case TeacKindTypeNoEnough:
{
[[UIColor clearColor] set];
}
break;
case TeacKindTypeTrue:
{
[[UIColor colorWithRed:94/255.0 green:195/255.0 blue:49/255.0 alpha:0.8] set];
}
그림 의 점 이 4 개 미 만 이면 선택 한 점 을 지우 고 경로 의 색 을 투명 하 게 그립 니 다(또는 성능 을 고려 하면 배경 색 과 같은 색 을 사용 하 는 것 이 좋 습 니 다).그림 이 완성 되면'녹색'으로 채 웁 니 다.여기 서 저 는 교사 가 그 려 진 경 로 를 잘 모 르 는 경 로 를 선택 하여 볼 수 있 습 니 다.학생 쪽 이 라면 올 바른 제거 경 로 를 그립 니 다.'빨간색'표지 경 로 를 잘못 사용 하고 잘못된 단 추 를 담 은 배열 self.errorBtns 에서 단 추 를 꺼 내 상 태 를 바 꿉 니 다.
switch (self.resultType) {
case ResultKindTypeTrue:
{
//
[[UIColor clearColor] set];
}
break;
case ResultKindTypeFalse:
{
//
[[UIColor redColor] set];
for (int i = 0; i < self.errorBtns.count; i++) {
UIButton *btn = [self.errorBtns objectAtIndex:i];
[btn setImage:[UIImage imageNamed:@"sign_img_circle_p"] forState:UIControlStateNormal];
}
break;
case ResultKindTypeNoEnough:
{
[[UIColor clearColor] set];
}
break;
case ResultKindTypeClear:
break;
default:
break;
}
그 다음 에 finish 가 없 으 면 경 로 를 그립 니 다.path 에 대해 관련 설정 을 합 니 다.
- (void)drawRect:(CGRect)rect {
if (_selectBtns.count == 0) return;
//
UIBezierPath *path = [UIBezierPath bezierPath];
for (int i = 0; i < self.selectBtns.count; i ++) {
UIButton *btn = self.selectBtns[i];
if (i == 0) {
[path moveToPoint:btn.center]; //
} else {
[path addLineToPoint:btn.center];
}
}
//
if (self.finished) {
//
NSMutableString *pwd = [self transferGestureResult];//
[[UIColor colorWithRed:94/255.0 green:195/255.0 blue:49/255.0 alpha:0.8] set];
if ([self.delegate respondsToSelector:@selector(gestureLockView:drawRectFinished:)]) {
[self.delegate gestureLockView:self drawRectFinished:pwd];
}
if (self.isTeac) {
//
switch (self.teacResultType) {
case TeacKindTypeNoEnough:
{
[[UIColor clearColor] set];
}
break;
case TeacKindTypeTrue:
{
[[UIColor colorWithRed:94/255.0 green:195/255.0 blue:49/255.0 alpha:0.8] set];
}
break;
default:
break;
}
} else {
switch (self.resultType) {
case ResultKindTypeTrue:
{
//
[[UIColor clearColor] set];
}
break;
case ResultKindTypeFalse:
{
//
[[UIColor redColor] set];
for (int i = 0; i < self.errorBtns.count; i++) {
UIButton *btn = [self.errorBtns objectAtIndex:i];
[btn setImage:[UIImage imageNamed:@"sign_img_circle_p"] forState:UIControlStateNormal];
}
break;
case ResultKindTypeNoEnough:
{
[[UIColor clearColor] set];
}
break;
case ResultKindTypeClear:
break;
default:
break;
}
}
}
} else {
[path addLineToPoint:self.currentPoint];
[[UIColor colorWithRed:94/255.0 green:195/255.0 blue:49/255.0 alpha:0.8] set];
}
path.lineWidth = 1;
path.lineJoinStyle = kCGLineCapRound;
path.lineCapStyle = kCGLineCapRound;
[path stroke];
}
ViewController이것 은 비교적 이해 하기 쉽다.각각 두 개의 화면 을 건너뛰다.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
TeacViewController *vc = [[TeacViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
} else {
StudViewController *vc = [[StudViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
}
TeacViewController주요 응용 프로그램 은 Gesture LockView Delegate 를 호출 하여 암 호 를 받 아들 이 고 검증 하 는 것 입 니 다.
#pragma mark gestureLockView
- (void)gestureLockView:(GestureLockView *)lockView drawRectFinished:(NSMutableString *)gesturePassword {
[self createGesturesPassword:gesturePassword];
}
//
- (void)createGesturesPassword:(NSMutableString *)gesturePassword {
if (self.lastGesturePsw.length == 0) {
if (gesturePassword.length < 4) {
self.lastGesturePsw = nil;
[self.gestureLockView checkTeacResult:TeacKindTypeNoEnough];
self.statusLabel.text = @" 4 , ";
[self shakeAnimationForView:self.statusLabel];
return;
}
self.lastGesturePsw = gesturePassword;
[self.gestureLockView checkTeacResult:TeacKindTypeTrue];
NSLog(@"---%@", self.lastGesturePsw);
self.statusLabel.text = [NSString stringWithFormat:@" %@", gesturePassword];
}
}
두 단추 의 클릭 이벤트
#pragma mark
//
- (void)resetBtnClick:(UIButton *)btn {
self.lastGesturePsw = nil;
[TeacViewController addGesturePassword:@""];
[self.gestureLockView checkTeacResult:TeacKindTypeNoEnough];
self.statusLabel.text = @" ";
NSLog(@"resetPwd == %@, resetUserDefaultsPwd == %@", self.lastGesturePsw, [TeacViewController gesturePassword]);
}
//
- (void)sureBtnClick:(UIButton *)btn {
if (!self.lastGesturePsw) {
self.statusLabel.text = @" ";
return;
}
[TeacViewController addGesturePassword:self.lastGesturePsw];
[self.gestureLockView checkTeacResult:TeacKindTypeTrue];
self.statusLabel.text = @" ";
NSLog(@"resetPwd == %@, resetUserDefaultsPwd == %@", self.lastGesturePsw, [TeacViewController gesturePassword]);
// [self.navigationController popViewControllerAnimated:YES];
}
로 컬 저장 소 로 시 뮬 레이 션 하기
#pragma mark
+ (void)deleteGestuesPassword {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:GESPWD];
[[NSUserDefaults standardUserDefaults] synchronize];
}
+ (void)addGesturePassword:(NSString *)gesturePassword {
[[NSUserDefaults standardUserDefaults] setObject:gesturePassword forKey:GESPWD];
[[NSUserDefaults standardUserDefaults] synchronize];
}
+ (NSString *)gesturePassword {
return [[NSUserDefaults standardUserDefaults] objectForKey:GESPWD];
}
StudViewControllerGesture LockDelegate 에이전트 방법 및 현재 제스처 암호 와 로 컬 에 저 장 된 교사 측 암 호 를 검사 합 니 다.
#pragma mark
- (void)gestureLockView:(GestureLockView *)lockView drawRectFinished:(NSMutableString *)gesturePassword {
[self validateGesturePassword:gesturePassword];
}
//
- (void)validateGesturePassword:(NSMutableString *)gesturePassword {
if (gesturePassword.length < 4) {
self.statusLabel.text = @" 4 , ";
[self.gestureLockView checkPwdResult:ResultKindTypeNoEnough];
[self shakeAnimationForView:self.statusLabel];
return;
}
self.lastGesturePsw = gesturePassword;
/* */
NSLog(@"validPwd == %@, validUserDefaultsPwd == %@", self.lastGesturePsw, [StudViewController gesturePassword]);
static NSInteger errorCount = 5;
if ([self.lastGesturePsw isEqualToString:[StudViewController gesturePassword]]) {
[self.gestureLockView checkPwdResult:ResultKindTypeTrue];
self.statusLabel.text = @" ";
[self shakeAnimationForView:self.statusLabel];
} else {
[self.gestureLockView checkPwdResult:ResultKindTypeFalse];
errorCount = errorCount - 1;
if (errorCount == 0) {
// 5
self.statusLabel.text = @" ";
errorCount = 5;
return;
}
self.statusLabel.text = [NSString stringWithFormat:@" , %ld ", errorCount];
[self shakeAnimationForView:self.statusLabel];
}
}
지우 기 단 추 를 누 르 면 이벤트 변경 self.gesture LockView 의 resultType 을 누 르 면 인터페이스 재 설정 등 을 조정 합 니 다.
- (void)clearBtnClick:(UIButton *)btn {
self.statusLabel.text = @" !!!";
[self.gestureLockView checkPwdResult:ResultKindTypeClear];
[self shakeAnimationForView:self.statusLabel];
}
로 컬 저장 소:여기 도 로 컬 저장 소 와 교사 측 이 대응 합 니 다.(사실은 따로 포장 할 수 있 습 니 다)
#pragma mark
+ (void)deleteGestuesPassword {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:GESPWD];
[[NSUserDefaults standardUserDefaults] synchronize];
}
+ (void)addGesturePassword:(NSString *)gesturePassword {
[[NSUserDefaults standardUserDefaults] setObject:gesturePassword forKey:GESPWD];
[[NSUserDefaults standardUserDefaults] synchronize];
}
+ (NSString *)gesturePassword {
return [[NSUserDefaults standardUserDefaults] objectForKey:GESPWD];
}
이상 은 바로 이 기능 이 실현 되 는 대체 적 인 절차 입 니 다.생각 을 정리 한 결과 아직도 명확 합 니 다.그 당시 에 할 때 도 구 덩이 를 파 서 구 덩이 를 메 웠 습 니 다.이렇게 자신의 생각 을 쓰 면 정말 얻 은 것 이 있 습 니 다.자신 이 더욱 발전 하 기 를 바 랍 니 다.만약 에 여기 서 불합리한 부분 이 있다 고 생각 되면 언제든지 저 와 소통 하 는 것 을 환영 합 니 다.소스 코드 연결:https://github.com/irembeu/LGJGestureLockDemo.git
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
View의 레이아웃 방법을 AutoLayout에서 따뜻한 손 계산으로 하면 성능이 9.26배로 된 이야기이 기사는 의 15 일째 기사입니다. 어제는 에서 이었습니다. 손 계산을 권하는 의도는 없고, 특수한 상황하에서 계측한 내용입니다 화면 높이의 10 배 정도의 contentView가있는 UIScrollView 레이아...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.