안 드 로 이 드 리더 장 선택 문자 기능 구현 코드
우선 효과 도 를 살 펴 보 자.
사람 에 게 물고 기 를 가 르 치 는 것 보다 사람 에 게 물고 기 를 가 르 치 는 것 이 낫다.다음은 원 리 를 구체 적 으로 실현 하 는 교과 과정 이다.
1.실현 원리
원 리 는 사실 어렵 지 않다.간단하게 요약 하면 문 자 를 그 릴 때 표 시 된 문자 의 좌 표를 기록 하 는 것 이다(문자 의 왼쪽 위,오른쪽 아래 네 개의 점 좌 표를 기록 하 는 것).작용 은 바로 미끄럼 범 위 를 계산 하기 위 한 것 이다.이벤트 에 길 게 누 른 후 누 른 좌 표를 통 해 현재 표 시 된 문자 데이터 에서 점 의 좌표 에 따라 누 른 글 자 를 찾 고 길 게 누 른 후에 선택 한 위치 와 문 자 를 얻 을 수 있 습 니 다.미끄럼 선택 을 실행 할 때 손가락 이 미 끄 러 지 는 위치 좌표 에 따라 현재 표 시 된 텍스트 데이터 와 일치 하여 선택 한 범위 와 텍스트 를 확인 합 니 다.
2.구체 적 실현
봉인
조작 하기 편리 하도록 먼저 보 이 는 문자,보 이 는 줄 데 이 터 를 봉인 합 니 다.
ShowChar:
public class ShowChar {//
public char chardata ;//
public Boolean Selected =false;//
public Point TopLeftPosition = null;
public Point TopRightPosition = null;
public Point BottomLeftPosition = null;
public Point BottomRightPosition = null;
public float charWidth = 0;//
public int Index = 0;//
}
ShowLine :
public class ShowLine {//
public List<ShowChar> CharsData = null;
/**
*@return
*--------------------
*TODO
*--------------------
*/
public String getLineData(){
String linedata = "";
if(CharsData==null||CharsData.size()==0) return linedata;
for(ShowChar c:CharsData){
linedata = linedata+c.chardata;
}
return linedata;
}
}
설명:리더 가 데 이 터 를 한 줄 한 줄 로 표시 합 니 다.줄 마다 수량 이 불확실 한 문자 가 있 습 니 다.모든 문 자 는 자신의 정 보 를 가지 고 있 습 니 다.예 를 들 어 문자 너비,문자 가 데이터 집합 에서 의 아래 표지 등 입 니 다.그 릴 때 ShowLine 을 그 려 서 줄 마다 데 이 터 를 그립 니 다.b.데이터 변환
그림 을 그리 기 전에,우 리 는 먼저 데 이 터 를 위 에 봉 인 된 형식 데이터 로 바 꾸 어 우리 가 사용 할 수 있 도록 해 야 한다.이거 어떻게 해 야 돼?문자열 을 한 줄 한 줄 의 데이터 로 바 꾸 고 모든 문자 의 문자 폭 을 측정 해 야 하기 때 문 입 니 다.그림 그리 기 에 익숙 하 다 면 시스템 에 paint.measuretext 가 문자 의 폭 을 측정 할 수 있다 는 것 을 알 수 있 을 것 입 니 다.이 를 통 해 문자 의 폭 을 측정 하 는 동시에 우리 가 원 하 는 줄 데이터 로 전환 할 수 있 습 니 다.
우선,들 어 오 는 문자열 을 줄 데이터 로 바 꿀 수 있 는 방법 을 쓰 십시오.
/**
*@param cs
*@param medsurewidth
*@param textpadding
*@param paint
*@return cs 0, null
*--------------------
*TODO
*--------------------
*/
public static BreakResult BreakText(char[] cs, float medsurewidth, float textpadding, Paint paint) {
if(cs==null||cs.length==0){return null;}
BreakResult breakResult = new BreakResult();
breakResult.showChars = new ArrayList<ShowChar>();
float width = 0;
for (int i = 0, size = cs.length; i < size; i++) {
String mesasrustr = String.valueOf(cs[i]);
float charwidth = paint.measureText(mesasrustr);
if (width <= medsurewidth && (width + textpadding + charwidth) > medsurewidth) {
breakResult.ChartNums = i;
breakResult.IsFullLine = true;
return breakResult;
}
ShowChar showChar = new ShowChar();
showChar.chardata = cs[i];
showChar.charWidth = charwidth;
breakResult.showChars.add(showChar);
width += charwidth + textpadding;
}
breakResult.ChartNums = cs.length;
return breakResult;
}
public static BreakResult BreakText(String text, float medsurewidth, float textpadding, Paint paint) {
if (TextUtils.isEmpty(text)) {
int[] is = new int[2];
is[0] = 0;
is[1] = 0;
return null;
}
return BreakText(text.toCharArray(), medsurewidth, textpadding, paint);
}
설명:BreakResult 는 측정 결과 에 대한 간단 한 패키지 입 니 다.
public class BreakResult {
public int ChartNums = 0;//
public Boolean IsFullLine = false;//
public List<ShowChar> showChars = null;//
public Boolean HasData() {
return showChars != null && showChars.size() > 0;
}
}
위의 작업 을 완성 한 후에 우 리 는 우리 가 표시 한 데 이 터 를 필요 한 데이터 로 바 꿀 수 있다.다음은 테스트 에 표 시 된 문자열 입 니 다:
String TextData = "jEh , , 。 , 。 , 、 , 。 , , , , 。 , 、 。 , 。 , , 、 。 , 、 , , , "
+
" , 。 , 。 , , 。 , , 。 , 。 , , , 。 , ; , , 。 , 。 , , 。 , ; , 。 , 。 , , , , 。 , 。 , ; , 。 、 、 、 、 、 、 、 、 、 , “ ”。 , “ ”。 , , 。";
이 문자열 을 줄 데이터 로 바 꿔 야 합 니 다.데 이 터 를 초기 화 하 는 작업 입 니 다.다음은 데 이 터 를 초기 화 하 는 방법 initData 입 니 다.
List<ShowLine> mLinseData = null;
private void initData(int viewwidth, int viewheight) {
if (mLinseData == null) {
//
mLinseData = BreakText(viewwidth, viewheight);
}
}
private List<ShowLine> BreakText(int viewwidth, int viewheight) {
List<ShowLine> showLines = new ArrayList<ShowLine>();
while (TextData.length() > 0) {
BreakResult breakResult = TextBreakUtil.BreakText(TextData, viewwidth, 0, mPaint);
if (breakResult != null && breakResult.HasData()) {
ShowLine showLine = new ShowLine();
showLine.CharsData = breakResult.showChars;
showLines.add(showLine);
} else {
break;
}
TextData = TextData.substring(breakResult.ChartNums);
}
int index = 0;
for (ShowLine l : showLines) {
for (ShowChar c : l.CharsData) {
c.Index = index++;
}
}
return showLines;
}
initData 방법 을 호출 하면 TextData 의 데 이 터 를 표시 하 는 줄 데이터 Linedata 집합 mLinsedata 로 변환 할 수 있 습 니 다.주의해 야 할 것 은 이 방법 을 사용 하려 면 컨트롤 의 길 이 를 알 아야 합 니 다.view 의 수명 주기 에 따라 onmeasures 에서 이 방법 을 사용 하여 초기 화 할 수 있 습 니 다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int viewwidth = getMeasuredWidth();
int viewheight = getMeasuredHeight();
initData(viewwidth, viewheight);
}
데이터 전환 이 완 료 된 후에 우 리 는 데 이 터 를 한 줄 한 줄 그 려 야 한다.
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
LineYPosition = TextHeight + LinePadding;// y
for (ShowLine line : mLinseData) {
DrawLineText(line, canvas);// ,
}
}
DrawLine Text 방법:
private void DrawLineText(ShowLine line, Canvas canvas) {
canvas.drawText(line.getLineData(), 0, LineYPosition, mPaint);
float leftposition = 0;
float rightposition = 0;
float bottomposition = LineYPosition + mPaint.getFontMetrics().descent;
for (ShowChar c : line.CharsData) {
rightposition = leftposition + c.charWidth;
Point tlp = new Point();
c.TopLeftPosition = tlp;
tlp.x = (int) leftposition;
tlp.y = (int) (bottomposition - TextHeight);
Point blp = new Point();
c.BottomLeftPosition = blp;
blp.x = (int) leftposition;
blp.y = (int) bottomposition;
Point trp = new Point();
c.TopRightPosition = trp;
trp.x = (int) rightposition;
trp.y = (int) (bottomposition - TextHeight);
Point brp = new Point();
c.BottomRightPosition = brp;
brp.x = (int) rightposition;
brp.y = (int) bottomposition;
leftposition = rightposition;
}
LineYPosition = LineYPosition + TextHeight + LinePadding;
}
실행 하 십시오.현재 표시 효 과 는 다음 과 같 습 니 다.이 를 실현 한 후 에는 긴 선택 기능 과 미끄럼 선택 문자 기능 이 필요 하 다.어떻게 길 게 누 를 수 있 습 니까?스스로 쓰 면 될 것 입 니 다.다만 너무 번 거 로 울 뿐 입 니 다.그래서 우 리 는 시스템 이 제공 하 는 길 게 누 르 는 사건 을 빌 리 면 됩 니 다.내 가 실현 한 사고방식 은 이렇다.먼저 사건 처리 모델 을 네 가지 로 나눈다.
private enum Mode {
Normal, //
PressSelectText,//
SelectMoveForward, //
SelectMoveBack//
}
어떠한 처리 도 하지 않 은 상태 에서 Normal 모드 입 니 다.제스처 가 발생 하면 Down 이벤트 가 촉발 되 고 현재 Down 의 좌 표를 기록 합 니 다.만약 에 사용자 가 계속 누 르 면 반드시 긴 이벤트 가 발생 하고 모드 는 PressSelectText 로 바 뀌 며 기 록 된 Down 의 좌 표를 통 해 데이터 집합 에서 현재 긴 문 자 를 찾 아 선택 한 문자 의 배경 을 그립 니 다.생각 이 이 렇 습 니 다.그럼 하 세 요.우선 등록 장 은 이벤트 에 따라 이 사건 을 초기 화 합 니 다.
private void init() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(29);
mTextSelectPaint = new Paint();
mTextSelectPaint.setAntiAlias(true);
mTextSelectPaint.setTextSize(19);
mTextSelectPaint.setColor(TextSelectColor);
mBorderPointPaint = new Paint();
mBorderPointPaint.setAntiAlias(true);
mBorderPointPaint.setTextSize(19);
mBorderPointPaint.setColor(BorderPointColor);
FontMetrics fontMetrics = mPaint.getFontMetrics();
TextHeight = Math.abs(fontMetrics.ascent) + Math.abs(fontMetrics.descent);
setOnLongClickListener(mLongClickListener);
}
private OnLongClickListener mLongClickListener = new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mCurrentMode == Mode.Normal) {
if (Down_X > 0 && Down_Y > 0) {// ,
mCurrentMode = Mode.PressSelectText;
postInvalidate();//
}
}
return false;
}
};
여기 다운X , Down_Y ; 초기 화 값 은 모두-1 입 니 다.다운 이 벤트 를 실행 하면 0 이상 일 것 입 니 다.Action 을 실행 하면up 이벤트,설정 값 을-1 로 방출 합 니 다.판단 을 위해 사용 할 뿐 입 니 다.그리고 onDraw 에서 선택 한 문 자 를 판단 하고 그 려 야 합 니 다.
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
LineYPosition = TextHeight + LinePadding;// y
for (ShowLine line : mLinseData) {
DrawLineText(line, canvas);//
}
if (mCurrentMode != Mode.Normal) {
DrawSelectText(canvas);// ,
}
}
private void DrawSelectText(Canvas canvas) {
if (mCurrentMode == Mode.PressSelectText) {
DrawPressSelectText(canvas);//
} else if (mCurrentMode == Mode.SelectMoveForward) {//
DrawMoveSelectText(canvas);//
} else if (mCurrentMode == Mode.SelectMoveBack) {//
DrawMoveSelectText(canvas);//
}
}
이 때 이벤트 가 길 게 실행 되면 mCurrentMode=Mode.PressSelectText 는 길 게 선택 한 문 자 를 그립 니 다.
//
private void DrawPressSelectText(Canvas canvas) {
//
ShowChar p = DetectPressShowChar(Down_X, Down_Y);
if (p != null) {//
FirstSelectShowChar = LastSelectShowChar = p;
mSelectTextPath.reset();
mSelectTextPath.moveTo(p.TopLeftPosition.x, p.TopLeftPosition.y);
mSelectTextPath.lineTo(p.TopRightPosition.x, p.TopRightPosition.y);
mSelectTextPath.lineTo(p.BottomRightPosition.x, p.BottomRightPosition.y);
mSelectTextPath.lineTo(p.BottomLeftPosition.x, p.BottomLeftPosition.y);
//
canvas.drawPath(mSelectTextPath, mTextSelectPaint);
//
DrawBorderPoint(canvas);
}
}
클릭 점 이 있 는 문자 검사 방법:
/**
*@param down_X2
*@param down_Y2
*@return
*--------------------
*TODO , null
*--------------------
*/
private ShowChar DetectPressShowChar(float down_X2, float down_Y2) {
for (ShowLine l : mLinseData) {
for (ShowChar c : l.CharsData) {
if (down_Y2 > c.BottomLeftPosition.y) {
break;//
}
if (down_X2 >= c.BottomLeftPosition.x && down_X2 <= c.BottomRightPosition.x) {
return c;
}
}
}
return null;
}
기본적으로 이벤트 에 따라 작업 이 완료 되 었 습 니 다.우 리 는 문자 에 따라 효 과 를 봅 니 다.선택 한 문 자 를 길 게 그 린 후에 우 리 는 좌우 의 지시 블록 에 따라 좌우 또는 상하 로 미 끄 러 지 며 문 자 를 선택해 야 합 니 다.조작 하기 편리 하도록 위로 미 끄 러 지 거나 아래로 미 끄 러 지 는 것 은 모두 미끄럼 범 위 를 제한 합 니 다.다음 과 같은 그림 입 니 다.
파란색 구역 은 손가락 을 누 른 후 터치 하여 미끄럼 을 허용 합 니 다.왼쪽 에 있 는 작은 파란색 구역 을 누 르 면 mCurrent Mode=Mode.selectMove Forward 는 위로 미 끄 러 지 며 텍스트 를 선택 할 수 있 습 니 다.바로 손가락 이 미 끄 러 지 는 좌표 가 노란색 구역 으로 미 끄 러 지 는 것 이 유효 합 니 다.오른쪽 에 있 는 작은 파란색 구역 을 누 르 면 mCurrent Mode==Mode.selectMoveBack,아래로 미 끄 러 지 며 텍스트 를 선택 할 수 있 습 니 다.바로 손가락 이 녹색 구역 으로 미 끄 러 지 는 것 이 유효 합 니 다.
선택 할 때 우 리 는 두 글자 만 기록 합 니 다.바로 선택 한 문자 의 시작 문자 와 끝 문자 입 니 다.
private ShowChar FirstSelectShowChar = null;
private ShowChar LastSelectShowChar = null;
길 게 누 르 면 문 자 를 선택 한 후:First SelectShow Char=LastSelectShow Char;따라서 전체 과정 은 미 끄 러 질 때 왼쪽 파란색 구역 을 누 르 면 앞으로 미 끄 러 질 수 있 습 니 다.이때 mCurrent Mode=Mode.selectMoveForward 는 앞으로 미 끄 러 지 는 것 이 노란색 구역 에서 미 끄 러 지 는 것 입 니 다.이때 손가락 이 미 끄 러 지 는 좌표 에 따라 미 끄 러 진 FirstSelectShow Char 를 찾 은 다음 에 화면 을 새로 고 칠 수 있 습 니 다.아래로 미 끄 러 지 는 것 은 이치 에 맞다.
다음은 코드 구현:
먼저 ActionDown 에 서 는 아래로 미 끄 러 지 는 지 아래로 미 끄 러 지 는 지 판단 합 니 다.그렇지 않 으 면 리 셋 하여 선택 한 텍스트 를 원상 태 로 복원 합 니 다.
case MotionEvent.ACTION_DOWN:
Down_X = Tounch_X;
Down_Y = Tounch_Y;
if (mCurrentMode != Mode.Normal) {
Boolean isTrySelectMove = CheckIfTrySelectMove(Down_X, Down_Y);
if (!isTrySelectMove) {// , ,
mCurrentMode = Mode.Normal;
invalidate();
}
}
break;
미 끄 러 질 때 판단 합 니 다.위로 미 끄 러 지 는 경우 현재 미 끄 러 질 때의 First SelectShowChar 가 져 오기;아래로 미 끄 러 지면 현재 미 끄 러 질 때의 LastSelectShow Char 를 가 져 온 다음 화면 을 새로 고 칩 니 다.
case MotionEvent.ACTION_MOVE:
if (mCurrentMode == Mode.SelectMoveForward) {
if (CanMoveForward(event.getX(), event.getY())) {//
ShowChar firstselectchar = DetectPressShowChar(event.getX(), event.getY());//
if (firstselectchar != null) {
FirstSelectShowChar = firstselectchar;
invalidate();
}
}
} else if (mCurrentMode == Mode.SelectMoveBack) {
if (CanMoveBack(event.getX(), event.getY())) {//
ShowChar lastselectchar = DetectPressShowChar(event.getX(), event.getY());//
if (lastselectchar != null) {
LastSelectShowChar = lastselectchar;
invalidate();
}
}
}
break;
위로 미 끄 러 지 는 방법 판단:
private boolean CanMoveForward(float Tounchx, float Tounchy) {
Path p = new Path();
p.moveTo(LastSelectShowChar.TopRightPosition.x, LastSelectShowChar.TopRightPosition.y);
p.lineTo(getWidth(), LastSelectShowChar.TopRightPosition.y);
p.lineTo(getWidth(), 0);
p.lineTo(0, 0);
p.lineTo(0, LastSelectShowChar.BottomRightPosition.y);
p.lineTo(LastSelectShowChar.BottomRightPosition.x, LastSelectShowChar.BottomRightPosition.y);
p.lineTo(LastSelectShowChar.TopRightPosition.x, LastSelectShowChar.TopRightPosition.y);
return computeRegion(p).contains((int) Tounchx, (int) Tounchy);
}
아래로 미 끄 러 질 지 판단 하기:
private boolean CanMoveBack(float Tounchx, float Tounchy) {
Path p = new Path();
p.moveTo(FirstSelectShowChar.TopLeftPosition.x, FirstSelectShowChar.TopLeftPosition.y);
p.lineTo(getWidth(), FirstSelectShowChar.TopLeftPosition.y);
p.lineTo(getWidth(), getHeight());
p.lineTo(0, getHeight());
p.lineTo(0, FirstSelectShowChar.BottomLeftPosition.y);
p.lineTo(FirstSelectShowChar.BottomLeftPosition.x, FirstSelectShowChar.BottomLeftPosition.y);
p.lineTo(FirstSelectShowChar.TopLeftPosition.x, FirstSelectShowChar.TopLeftPosition.y);
return computeRegion(p).contains((int) Tounchx, (int) Tounchy);
}
private Region computeRegion(Path path) {
Region region = new Region();
RectF f = new RectF();
path.computeBounds(f, true);
region.setPath(path, new Region((int) f.left, (int) f.top, (int) f.right, (int) f.bottom));
return region;
}
제스처 처리 가 완료 되 었 습 니 다.나머지 는 ondraw 에서 mCurrent Mode==Mode.selectMove Forward 또는 mCurrent Mode==Mode.selectMoveBack 에서 선택 한 범위 배경 을 그립 니 다.
private void DrawSelectText(Canvas canvas) {
if (mCurrentMode == Mode.PressSelectText) {
DrawPressSelectText(canvas);//
} else if (mCurrentMode == Mode.SelectMoveForward) {//
DrawMoveSelectText(canvas);//
} else if (mCurrentMode == Mode.SelectMoveBack) {//
DrawMoveSelectText(canvas);//
}
}
private void DrawMoveSelectText(Canvas canvas) {
if (FirstSelectShowChar == null || LastSelectShowChar == null) return;
GetSelectData();// ,
DrawSeletLines(canvas);//
DrawBorderPoint(canvas);//
}
private void DrawSeletLines(Canvas canvas)
DrawOaleSeletLinesBg(canvas);
}
private void DrawOaleSeletLinesBg(Canvas canvas) {//
for (ShowLine l : mSelectLines) {
if (l.CharsData != null && l.CharsData.size() > 0) {
ShowChar fistchar = l.CharsData.get(0);
ShowChar lastchar = l.CharsData.get(l.CharsData.size() - 1);
float fw = fistchar.charWidth;
float lw = lastchar.charWidth;
RectF rect = new RectF(fistchar.TopLeftPosition.x, fistchar.TopLeftPosition.y,
lastchar.TopRightPosition.x, lastchar.BottomRightPosition.y);
canvas.drawRoundRect(rect, fw / 2,
TextHeight / 2, mTextSelectPaint);
}
}
}
기본적으로 완성 되 었 으 니 운행 해 보 세 요.효과 가 괜 찮 습 니 다.이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.