android自定义简易英文文章阅读器,支持点击查单词

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/lylddingHFFW/article/details/99310078

本文主要说明一个简易的英文文章阅读器实现逻辑(^^)

一:基本逻辑

整体逻辑为TextView+ViewFlipper
1:实现页面中单词点击选中
2:实现分页功能
3:实现简单的翻页动画
原文地址

GitHub测试Demo

第一步:实现页面中单词点击选中功能。

自定义阅读页面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);
}

猜你喜欢

转载自blog.csdn.net/lylddingHFFW/article/details/99310078