本文主要说明一个简易的英文文章阅读器实现逻辑(^^)
一:基本逻辑
整体逻辑为TextView+ViewFlipper
1:实现页面中单词点击选中
2:实现分页功能
3:实现简单的翻页动画
原文地址
第一步:实现页面中单词点击选中功能。
自定义阅读页面ReaderPage extends TextView
因为要有单词点击事件,需要设置setMovementMethod(LinkMovementMethod.getInstance());
但这样会有TextView的滑动和点击单词文本的冲突。 原因及解决方案地址
1获取文本分词
/**
*英文文本获取所有单词
*/
public List<String> splitWord(@NonNull String text) {
if (TextUtils.isEmpty(text)) {
return new ArrayList<>();
}
List<String> words= new ArrayList<>();
Pattern pattern = Pattern.compile("[a-zA-Z-']+");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
words.add(matcher.group(0));
}
return words;
}
2获取单词在文本中的位置
private List<WordInfo> getWordInfos(String text) {
List<String> words = splitWord(text);
List<WordInfo> wordInfos = new ArrayList<>(words.size());
int startIndex = 0;
for (int i = 0; i < words.size(); i++) {
String word = words.get(i);
int start = text.indexOf(word, startIndex);
int end = start + word.length();
startIndex = end;
WordInfo wordInfo = new WordInfo();
wordInfo.setStart(start);
wordInfo.setEnd(end);
wordInfo.setWord(word);
wordInfos.add(wordInfo);
}
return wordInfos;
}
3设置单词点击事件
private void setClickableSpans() {
for (int i = 0; i < mWordInfos.size(); i++) {
WordInfo info = mWordInfos.get(i);
mSpannableString.setSpan(new WordClickableSpan(info),
info.getStart(), info.getEnd(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
第二步:实现分页功能
阅读器 Reader extends ViewFlipper
通过readerPage 对所用文本进行测量,计算总行数和每页显示行数,可以得到总页数。(此方法不适合数据量特别多的文本,有合适的思路,请多多指教)
耗时操作,建议在新线程中处理
public void computeBookTextInfo(Context context, String allText {
ReaderPage readerPage = new ReaderPage (context);
readerPage .setText(allText );
//这里根据实际需求进行测量
readerPage .measure(widthMeasureSpec, heightMeasureSpec);
Layout layout = readerPage .getLayout();
int offset = readerPage .getMeasuredHeight() - readerPage .getPaddingBottom() - readerPage .getPaddingTop();
//总行数
mAllLines = layout.getLineCount();
//每一页行数
mPerPageLines = layout.getLineForVertical(offset) - 1;
//总页数
mTotalPages= mPerPageLines == 0 ? 0 : mAllLines / mPerPageLines + 1;
if (mTotalPages<= 0) {
return;
}
mPageInfos = new ArrayList<>(mTotalPages);
int start = 0;
int endLine;
//计算每页信息
for (int index = 0; index < mTotalPages; index++) {
PageInfo pageInfo = new PageInfo();
pageInfo.setPageNum(index);
pageInfo.setStart(start);
if (index + 1 < mTotalPages) {
endLine = mPerPageLines * (index + 1) - 1;
start = layout.getLineStart(endLine + 1);
} else {
endLine = mAllLines - 1;
}
pageInfo.setEnd(layout.getLineEnd(endLine));
pageInfo.setText(allText .substring(pageInfo.getStart(), pageInfo.getEnd()));
mPageInfos.add(pageInfo);
}
}
第三步:实现简单的翻页动画
父类为ViewFlipper,根据滑动事件进行左滑右滑,滑进滑出动画的动态添加。
1处理点击事件在子View中
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = event.getX();
mDownY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
if (event.getX() - mDownX > THRESHOLD) {
fromLeftToRight();
} else if (event.getX() - mDownX < -THRESHOLD) {
romRightToLeft();
}
break;
default:
}
return super.onInterceptTouchEvent(event);
}
2点击事件在自身
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = event.getX();
mDownY = event.getY();
return true;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
if (Math.abs(event.getX() - mDownX) < mTouchSlop) {
if (mListener != null) {
mListener .onClickWord(this, Empty);
}
} else {
if (event.getX() - mDownX > THRESHOLD) {
fromLeftToRight();
} else if (event.getX() - mDownX < -THRESHOLD) {
fromRightToLeft();
}
}
break;
default:
}
return super.onTouchEvent(event);
}