Android 사용자 정의 view 화려 한 인증 코드 만 들 기
어 떻 습 니까?이런 인증 코드 는 흔 하지 않 습 니까?다음은 우리 가 직접 이런 효 과 를 실현 하고 스스로 손 을 써 서 풍족 하 게 먹 겠 습 니 다.하하~
1.사용자 정의 view 의 절차
사용자 정의 view 는 안 드 로 이 드 진급 이 고수 로 가 는 데 필수 적 인 길이 라 고 여 겨 져 왔 습 니 다.사실 사용자 정의 view 는 매우 간단 합 니 다.사용자 정의 view 가 정말 어 려 운 것 은 고난 도 도형 을 어떻게 그 리 는 지 하 는 것 입 니 다.이것 은 좋 은 수학 기초(수학 을 잘 배우 지 못 한 것 을 후회 합 니 다~)가 필요 합 니 다.도형 을 그 리 는 데 좌표 점 과 유사 한 기하학 적 변환 등 을 자주 계산 해 야 하기 때 문 입 니 다.사용자 정의 view 는 보통 다음 과 같은 몇 가지 절차 만 필요 합 니 다.
클래스 계승 View 클래스 쓰기;
다시 보기 의 구조 방법;
View 의 크기 를 측정 하 는 것,즉 onMeasure()방법 을 다시 쓰 는 것 입 니 다.
다시 onDraw()방법.
그 중에서 세 번 째 단 계 는 필수 적 인 것 이 아 닙 니 다.시스템 이 사용자 정의 view 의 크기 를 정할 수 없 을 때 만 사용자 정의 view 크기 를 재 작성 해 야 합 니 다.사용자(프로그래머)가 사용자 정의 view 를 사용 할 때 정확 한 크기(너비 나 높이)를 지정 하지 않 았 기 때 문 입 니 다.예 를 들 어 레이아웃 파일 에서 layotwidth 또는 layotheigth 속성 치 는 wrapmatch 가 아 닌 contentparent 또는 정확 한 값 입 니 다.시스템 은 view 가 onDraw()에 그 려 진 그림 의 크기 를 모 르 기 때문에 사용자 정의 view 가 wrap 을 지원 합 니 다.content 그러면 우 리 는 onMeasure 방법 을 다시 써 서 시스템 에 우리 가 그 릴 view 의 크기(너비 와 높이)를 알려 야 합 니 다.
또한,사용자 정의 view 에 특별한 속성 이 필요 하 다 면 사용자 정의 속성 이 필요 합 니 다.이 글 은 사용자 정의 속성 과 위의 네 단계 의 내용 과 관련 될 것 입 니 다.
2.사용자 정의 view 의 실현
이러한 인증 코드 컨트롤 을 실현 하려 면,우 리 는 먼저 그것 이 어떻게 실현 되 는 지 분석 해 야 한다.위의 효과 도 를 보면 우 리 는 이러한 효 과 를 실현 하려 면 먼저 인증 코드 문자열,즉 그림 의 텍스트 부분 을 그 린 다음 에 간섭 점 을 그 린 다음 에 간섭 선 을 그 려 야 한 다 는 것 을 알 수 있다.분석 이 끝났다.다음 에 우 리 는 분석 결과 에 따라 이런 효 과 를 점차적으로 실현 한다.
1.뷰 계승,구조 재 작성 방법
계승 View 를 작성 한 다음 구조 방법 을 다시 작성 합 니 다.
/**
* Created by lt on 2016/3/2.
*/
public class ValidationCode extends View{
/**
* java view , new
* @param context
*/
public ValidationCode(Context context) {
this(context,null);
}
/**
* xml view style
* @param context
* @param attrs
*/
public ValidationCode(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* xml view style
* @param context
* @param attrs
* @param defStyleAttr
*/
public ValidationCode(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//
init();
}
}
View 는 세 가지 구조 방법 이 있 는데 일반적인 방법 은 하나의 매개 변수 와 두 개의 매개 변수의 구조 방법 으로 세 개의 구조 적 매개 변 수 를 호출 하 는 방법 이다.이 세 가지 구조 방법의 호출 상황 은 방법 위의 주석 을 본다.이 구조 방법 에서 우 리 는 먼저 랜 덤 인증 코드 문자열,화필 등 을 초기 화 하 는 작업 을 한다.
/**
*
*/
private void init() {
//
mCodeString = getCharAndNumr(mCodeCount);
//
mTextPaint = new Paint();
mTextPaint.setStrokeWidth(3); // 3
mTextPaint.setTextSize(mTextSize); //
//
mPointPaint = new Paint();
mPointPaint.setStrokeWidth(6);
mPointPaint.setStrokeCap(Paint.Cap.ROUND); //
//
mPathPaint = new Paint();
mPathPaint.setStrokeWidth(5);
mPathPaint.setColor(Color.GRAY);
mPathPaint.setStyle(Paint.Style.STROKE); //
mPathPaint.setStrokeCap(Paint.Cap.ROUND); //
//
mTextWidth = mTextPaint.measureText(mCodeString);
}
여기까지 사용자 정의 View 단계 의 앞 두 단 계 를 완 성 했 습 니 다.다음은 세 번 째 단계 입 니 다.즉,onMeasure()를 다시 써 서 사용자 정의 view 크기(너비)를 측정 하 는 것 입 니 다.2.onMeasure()를 다시 쓰 고 View 크기 측정 완료
/**
* layout_width layout_height wrap_content
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// ,
int measureWidth = measureWidth(widthMeasureSpec);
int measureHeight = measureHeight(heightMeasureSpec);
// setMeasuredDimension(int measureWidth,int measureHeight);
//
setMeasuredDimension(measureWidth, measureHeight);
}
너비 측정 방법:
/**
*
* @param widthMeasureSpec
*/
private int measureWidth(int widthMeasureSpec) {
int result = (int) (mTextWidth*1.8f);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
if(widthMode == MeasureSpec.EXACTLY){
// , layout_width layout_height match_parent
result = widthSize; // ,
}else{
if(widthMode == MeasureSpec.AT_MOST) {
// , layout_width layout_height wrap_content
result = Math.min(result,widthSize);
}
}
return result;
}
높이 측정 방법:
/**
*
* @param heightMeasureSpec
*/
private int measureHeight(int heightMeasureSpec) {
int result = (int) (mTextWidth/1.6f);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if(heightMode == MeasureSpec.EXACTLY){
// , layout_width layout_height match_parent
result = heightSize; // ,
}else{
if(heightMode == MeasureSpec.AT_MOST) {
// , layout_width layout_height wrap_content
result = Math.min(result,heightSize);
}
}
return result;
}
설명:사실 onMeasure()방법 은 최종 적 으로 set Measured Dimension(int measureWidth,int measure Height)을 호출 합 니 다.측정 한 너비 와 높이 를 설정 하여 측정 을 완성 하 는 것 입 니 다.우리 가 해 야 할 일 은 너비 와 높이 의 값 을 측정 하 는 것 입 니 다.너비 와 높이 를 측정 하 는 방법 은 사용자(프로그래머)가 우리 에 게 주지 않 은 컨트롤 에 정확 한 값(구체 적 인 수치 나 match)을 지정 하 는 것 이 가장 중요 합 니 다.parent)시 적당 한 너비 와 높이 이기 때문에 상기 너비 와 높이 를 측정 하 는 방법 은 기본적으로 템 플 릿 방법 입 니 다.해 야 할 일 은 result 의 적당 한 값 을 얻 는 것 입 니 다.여기 서 result 에 주 는 그 값 에 관심 을 가 질 필요 가 없습니다.이 값 은 컨트롤 에 따라 계산 한 적당 한 값(적당 하지 않 을 수도 있 습 니 다)이기 때 문 입 니 다.컨트롤 의 측정 이 완료 되 었 습 니 다.그 다음 에 우 리 는 컨트롤 의 그리 기 를 완성 해 야 합 니 다.즉,사용자 정의 view 의 핵심 단계 인 onDraw()방법 으로 그림 을 그립 니 다.
3.onDraw()를 다시 쓰 고 그림 그리 기
위의 분석 에 따 르 면 인증 코드 텍스트 문자열,간섭 점,간섭 선 을 그 려 야 합 니 다.간섭 점 과 간섭 선 은 좌표 와 경로 로 그 려 야 하기 때문에 그리 기 전에 랜 덤 간섭 점 좌표 와 간섭 선 경 로 를 초기 화 합 니 다.
private void initData() {
// ,
mHeight = getHeight();
mWidth = getWidth();
mPoints.clear();
//
for(int i=0;i<150;i++){
PointF pointF = new PointF(mRandom.nextInt(mWidth)+10,mRandom.nextInt(mHeight)+10);
mPoints.add(pointF);
}
mPaths.clear();
//
for(int i=0;i<2;i++){
Path path = new Path();
int startX = mRandom.nextInt(mWidth/3)+10;
int startY = mRandom.nextInt(mHeight/3)+10;
int endX = mRandom.nextInt(mWidth/2)+mWidth/2-10;
int endY = mRandom.nextInt(mHeight/2)+mHeight/2-10;
path.moveTo(startX,startY);
path.quadTo(Math.abs(endX-startX)/2,Math.abs(endY-startY)/2,endX,endY);
mPaths.add(path);
}
}
이 데이터 가 있 으 면 우 리 는 도형 을 그리 기 시작 할 수 있다.(1)인증 코드 텍스트 문자열 그리 기
인증 코드 텍스트 문자열 은 무 작위 로 생 성 되 기 때문에 코드 를 이용 하여 무 작위 로 인증 코드 를 생 성 해 야 합 니 다.
/**
* java
* @param length[ ]
* @return
*/
public static String getCharAndNumr(int length) {
String val = "";
Random random = new Random();
for (int i = 0; i < length; i++) {
//
String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
//
if ("char".equalsIgnoreCase(charOrNum)) {
//
int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
val += (char) (choice + random.nextInt(26));
} else if ("num".equalsIgnoreCase(charOrNum)) { //
val += String.valueOf(random.nextInt(10));
}
}
return val;
}
이런 코드 는 자바 의 기초 입 니 다.모두 가 알 아 볼 수 있 을 거 라 고 믿 습 니 다.알 아 볼 수 없어 도 괜 찮 습 니 다.이런 코드 는 인터넷 에서 마음대로 검색 하면 있 습 니 다.사실은 저도 인터넷 에서 직접 검색 한 것 입 니 다.헤헤~android 의 2D 그래 픽 api canvas 는 drawXXX()방법 을 제공 하여 다양한 그래 픽 을 그립 니 다.그 중에서 drawText()방법 으로 텍스트 를 그립 니 다.또한 drawPosText()는 주어진 좌표 점 에 텍스트 를 그립 니 다.drawTextOnPath()는 주어진 경로 에 도형 을 그립 니 다.위의 효과 도 를 자세히 살 펴 보면 텍스트 가 수평 이 아 닌 것,즉 경사 가 있 는 것 을 발견 할 수 있 습 니 다.그러면 우리 의 인증 코드 에 일정한 식별 난이 도 를 높 일 수 있 습 니 다.문자 경사 효 과 를 실현 하려 면 drawTextOnPath()를 통 해 주어진 경로 에서 텍스트 를 그 려 경사 효 과 를 얻 을 수 있 습 니 다.그러나 이런 방법 은 비교적 어렵 습 니 다(좌표 점 과 경 로 는 계산 하기 어렵 습 니 다).그래서..canvas 가 제공 하 는 위치 변환 방법 인 rorate()를 통 해 drawText()와 결합 하여 텍스트 경사 효 과 를 실현 할 수 있 습 니 다.
int length = mCodeString.length();
float charLength = mTextWidth/length;
for(int i=1;i<=length;i++){
int offsetDegree = mRandom.nextInt(15);
// 0 1, 1 ,
offsetDegree = mRandom.nextInt(2) == 1?offsetDegree:-offsetDegree;
canvas.save();
canvas.rotate(offsetDegree, mWidth / 2, mHeight / 2);
// ,+20
mTextPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20);canvas.drawText(String.valueOf(mCodeString.charAt(i - 1)), (i-1) * charLength * 1.6f+30, mHeight * 2 / 3f, mTextPaint);
canvas.restore();
}
이 코드 는 for 순환 을 통 해 인증 코드 문자열 의 모든 문 자 를 그립 니 다.한 문 자 를 그 릴 때마다 캔버스 를 무 작위 로 양음 각 도 를 회전 시 킨 다음 drawText()방법 으로 문 자 를 그립 니 다.모든 문자 의 출발점 좌 표 는 문자 의 길이 와 위치 에 따라 다 릅 니 다.이 계산 은 적당 하지 않 을 수도 있 습 니 다.주의해 야 할 것 은 캔버스 canvas 에 위치 변환 을 할 때마다 canvas.save()방법 을 사용 하여 이전에 그린 그림 을 저장 하고,그리 기 가 끝 난 후에 canvas.restore()를 사용 하여 캔버스 의 위 치 를 복원 하여 다음 에 그림 을 그 릴 때 이전 캔버스 의 위치 변화 로 인해 영향 을 받 지 않도록 해 야 한 다 는 것 이다.(2)방해 점 그리 기
// 1 --
for(PointF pointF : mPoints){
mPointPaint.setARGB(255,mRandom.nextInt(200)+20,mRandom.nextInt(200)+20,mRandom.nextInt(200)+20);
canvas.drawPoint(pointF.x,pointF.y,mPointPaint);
}
방해 점 에 랜 덤 색상 을 설정 한 후 랜 덤 으로 생 긴 점 의 좌표 에 따라 canvas.draw Point()를 이용 하여 점 을 그립 니 다.(3)간섭 선 그리 기
// 2 --
for(Path path : mPaths){
mPathPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20);
canvas.drawPath(path, mPathPaint);
}
간섭 선 붓 에 랜 덤 색상 을 설정 한 후 랜 덤 생 성 경로 에 따라 canvas.drawPath()를 이용 하여 베 어 셀 곡선 을 그 려 간섭 선 을 그립 니 다.4.onTouchEvent 재 작성,맞 춤 형 보기 이벤트
이 단 계 는 사용자 정의 View 를 클릭 할 때 맞 춤 형 View 이 벤트 를 완성 하기 위 한 것 입 니 다.사용자 가 인증 코드 컨트롤 을 클릭 할 때 인증 코드 의 텍스트 문자열 을 바 꿔 야 합 니 다.
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
//
mCodeString = getCharAndNumr(mCodeCount);
invalidate();
break;
default:
break;
}
return super.onTouchEvent(event);
}
OK,여기까지 우리 의 이 사용자 정의 View 는 기본적으로 완성 되 었 습 니 다.이 사용자 정의 View 는 확장 성 이 너무 떨 어 지고 맞 춤 형 이 너무 낮 으 며 사용자 정의 속성 을 약속 한 것 이 아니 냐 고 물 을 수 있 습 니 다.어디 갔 어?서 두 르 지 마 세 요.다음은 우리 자신의 View 속성 을 사용자 정의 하고 속성 을 사용자 정의 합 니 다.5.사용자 정의 속성,사용자 정의 View 의 맞 춤 형 성 향상
(1)자원 파일 attrs.xml 파일 에서 우리 의 속성 을 정의 합 니 다(집합)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="IndentifyingCode">
<attr name="codeCount" format="integer|reference"></attr>
<attr name="textSize" format="dimension"></attr>
</declare-styleable>
</resources>
설명:attrs.xml 파일 의 attr 노드 에서 우리 의 속성 을 정의 합 니 다.속성 을 정의 하려 면 name 속성 이 우리 의 속성 값 을 표시 하 는 동시에 format 속성 이 속성 값 을 표시 하 는 형식 이 필요 합 니 다.그 형식 은 여러 가지 가 있 습 니 다.속성 값 이 여러 가지 형식 을 사용 할 수 있다 면 형식 간 에"|"로 나 눌 수 있 습 니 다.
declare-styleable 노드 는 사용자 정의 속성 집합 을 정의 하 는 데 사 용 됩 니 다.name 속성 은 이 속성 집합 의 이름 을 지정 하여 임의로 사용 할 수 있 지만 일반적으로 사용자 정의 컨트롤 의 이름 입 니 다.
속성 이 정의 되 었 다 면(예 를 들 어 layotwidth),그러면 이 속성 을 직접 참조 할 수 있 습 니 다.형식 을 지정 하지 마 십시오.
(2)레이아웃 파일 에서 사용자 정의 속성 을 참조 하여 네 임 스페이스 를 도입 해 야 합 니 다.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:lt="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.lt.identifyingcode.ValidationCode
android:id="@+id/validationCode"
android:layout_width="wrap_content"
android:layout_centerInParent="true"
lt:textSize="25sp"
android:background="@android:color/darker_gray"
android:layout_height="wrap_content"/>
</RelativeLayout>
네 임 스페이스 를 도입 하려 면 현재 xmlns:lt="http://schemas.android.com/apk/res-auto"(lt 는 네 임 스페이스 이름 으로 바 꿀 수 있 습 니 다).예전 에 네 임 스페이스 방식 을 xmlns:custom=로 도입 할 수 있 습 니 다."http://schemas.android.com/apk/res/com.example.customview01",res 뒤의 가방 경 로 는 프로젝트 의 package 를 말 합 니 다."(3)구조 방법 에서 사용자 정의 속성 값 가 져 오기
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.IndentifyingCode);
mCodeCount = typedArray.getInteger(R.styleable.IndentifyingCode_codeCount, 5); // , 5
// , 20sp
mTextSize = typedArray.getDimension(R.styleable.IndentifyingCode_textSize, typedArray.getDimensionPixelSize(R.styleable.IndentifyingCode_textSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics())));
// , IO
typedArray.recycle();
OK,사용자 정의 속성 도 완성 되 었 습 니 다.값 도 얻 었 습 니 다.그러면 우 리 는 맞 춤 형 속성 값 을 우리 onDraw()가 그 릴 때 만 사용 하면 됩 니 다.사용자 정의 속성 은 이렇게 간단 합 니 다.여 기 를 보면 좀 혼 란 스 러 울 수 있 습 니 다.전체 코드 를 보고 정리 하 세 요.
package com.lt.identifyingcode;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.Random;
/**
* Created by lt on 2016/3/2.
*/
public class ValidationCode extends View{
/**
*
*/
private int mWidth;
/**
*
*/
private int mHeight;
/**
*
*/
private Paint mTextPaint; //
/**
*
*/
private ArrayList<PointF> mPoints = new ArrayList<PointF>();
private Random mRandom = new Random();;
/**
*
*/
private Paint mPointPaint;
/**
*
*/
private ArrayList<Path> mPaths = new ArrayList<Path>();
/**
*
*/
private Paint mPathPaint;
/**
*
*/
private String mCodeString;
/**
*
*/
private int mCodeCount;
/**
*
*/
private float mTextSize;
/**
*
*/
private float mTextWidth;
/**
* java view , new
* @param context
*/
public ValidationCode(Context context) {
this(context,null);
}
/**
* xml view style
* @param context
* @param attrs
*/
public ValidationCode(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* xml view style
* @param context
* @param attrs
* @param defStyleAttr
*/
public ValidationCode(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getAttrValues(context, attrs);
//
init();
}
/**
*
* @param context
*/
private void getAttrValues(Context context,AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.IndentifyingCode);
mCodeCount = typedArray.getInteger(R.styleable.IndentifyingCode_codeCount, 5); // , 5
// , 20sp
mTextSize = typedArray.getDimension(R.styleable.IndentifyingCode_textSize, typedArray.getDimensionPixelSize(R.styleable.IndentifyingCode_textSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics())));
// , IO
typedArray.recycle();
}
/**
* layout_width layout_height wrap_content
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// ,
int measureWidth = measureWidth(widthMeasureSpec);
int measureHeight = measureHeight(heightMeasureSpec);
// setMeasuredDimension(int measureWidth,int measureHeight);
//
setMeasuredDimension(measureWidth, measureHeight);
}
@Override
protected void onDraw(Canvas canvas) {
//
initData();
int length = mCodeString.length();
float charLength = mTextWidth/length;
for(int i=1;i<=length;i++){
int offsetDegree = mRandom.nextInt(15);
// 0 1, 1 ,
offsetDegree = mRandom.nextInt(2) == 1?offsetDegree:-offsetDegree;
canvas.save();
canvas.rotate(offsetDegree, mWidth / 2, mHeight / 2);
//
mTextPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20);
canvas.drawText(String.valueOf(mCodeString.charAt(i - 1)), (i-1) * charLength * 1.6f+30, mHeight * 2 / 3f, mTextPaint);
canvas.restore();
}
// 1 --
for(PointF pointF : mPoints){
mPointPaint.setARGB(255,mRandom.nextInt(200)+20,mRandom.nextInt(200)+20,mRandom.nextInt(200)+20);
canvas.drawPoint(pointF.x,pointF.y,mPointPaint);
}
// 2 --
for(Path path : mPaths){
mPathPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20);
canvas.drawPath(path, mPathPaint);
}
}
private void initData() {
// ,
mHeight = getHeight();
mWidth = getWidth();
mPoints.clear();
//
for(int i=0;i<150;i++){
PointF pointF = new PointF(mRandom.nextInt(mWidth)+10,mRandom.nextInt(mHeight)+10);
mPoints.add(pointF);
}
mPaths.clear();
//
for(int i=0;i<2;i++){
Path path = new Path();
int startX = mRandom.nextInt(mWidth/3)+10;
int startY = mRandom.nextInt(mHeight/3)+10;
int endX = mRandom.nextInt(mWidth/2)+mWidth/2-10;
int endY = mRandom.nextInt(mHeight/2)+mHeight/2-10;
path.moveTo(startX,startY);
path.quadTo(Math.abs(endX-startX)/2,Math.abs(endY-startY)/2,endX,endY);
mPaths.add(path);
}
}
/**
*
*/
private void init() {
//
mCodeString = getCharAndNumr(mCodeCount);
//
mTextPaint = new Paint();
mTextPaint.setStrokeWidth(3); // 3
mTextPaint.setTextSize(mTextSize); //
//
mPointPaint = new Paint();
mPointPaint.setStrokeWidth(6);
mPointPaint.setStrokeCap(Paint.Cap.ROUND); //
//
mPathPaint = new Paint();
mPathPaint.setStrokeWidth(5);
mPathPaint.setColor(Color.GRAY);
mPathPaint.setStyle(Paint.Style.STROKE); //
mPathPaint.setStrokeCap(Paint.Cap.ROUND); //
//
mTextWidth = mTextPaint.measureText(mCodeString);
}
/**
* java
* @param length[ ]
* @return
*/
public static String getCharAndNumr(int length) {
String val = "";
Random random = new Random();
for (int i = 0; i < length; i++) {
//
String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
//
if ("char".equalsIgnoreCase(charOrNum)) {
//
int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
val += (char) (choice + random.nextInt(26));
} else if ("num".equalsIgnoreCase(charOrNum)) { //
val += String.valueOf(random.nextInt(10));
}
}
return val;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
//
mCodeString = getCharAndNumr(mCodeCount);
invalidate();
break;
default:
break;
}
return super.onTouchEvent(event);
}
/**
*
* @param widthMeasureSpec
*/
private int measureWidth(int widthMeasureSpec) {
int result = (int) (mTextWidth*1.8f);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
if(widthMode == MeasureSpec.EXACTLY){
// , layout_width layout_height match_parent
result = widthSize; // ,
}else{
if(widthMode == MeasureSpec.AT_MOST) {
// , layout_width layout_height wrap_content
result = Math.min(result,widthSize);
}
}
return result;
}
/**
*
* @param heightMeasureSpec
*/
private int measureHeight(int heightMeasureSpec) {
int result = (int) (mTextWidth/1.6f);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if(heightMode == MeasureSpec.EXACTLY){
// , layout_width layout_height match_parent
result = heightSize; // ,
}else{
if(heightMode == MeasureSpec.AT_MOST) {
// , layout_width layout_height wrap_content
result = Math.min(result,heightSize);
}
}
return result;
}
/**
* , ( )
* @return
*/
public String getCodeString() {
return mCodeString;
}
}
결론:여기 서 사용자 정의 View 라 기보 다 는 도형 을 그 리 는 것 이 관건 입 니 다.관건 은 좌표 점 의 계산 입 니 다.여기 서 계산 좌표 가 좋 지 않 을 수도 있 습 니 다.이상 은 안 드 로 이 드 사용자 정의 view 를 공유 하여 화려 한 인증 코드 를 만 드 는 것 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다!좋 은 아이디어 나 조언 이 있 으 시 면 댓 글로 남 겨 주시 면 감사 하 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.