平常在ViewGroup中放一个textView组件,无可避免会出现textView内容过多而需要解决滑动冲突的问题.
大多数的做法就是再嵌套一个ScrollView来处理滑动冲突,而之所以用ScrollView的考虑无非就是处理是否滑动到边界,这么想想感觉不值得!
网上有很多介绍如何让TextView加载多内容时可滑动的文章,但是很少有解决其滑动冲突的文章.
今天就不说怎么支持滑动了,因为只是加一句
textView.setMovementMethod(ScrollingMovementMethod.getInstance());
既然支持了滑动,想必肯定也能在其中发现一二吧,于是翻开这个ScrollingMovementMethod类来,一眼就发现了这个方法
@Override
protected boolean bottom(TextView widget, Spannable buffer) {
return scrollBottom(widget, buffer);
}
继续跟踪看一眼,在BaseMovementMethod中就会发现结果
/**执行滚动到底部动作。滚动到文档底部
* Performs a scroll to bottom action.
* Scrolls to the bottom of the document.
*
* @param widget The text view.
* @param buffer The text buffer.
* @return True if the event was handled.
* @hide
*/
protected boolean scrollBottom(TextView widget, Spannable buffer) {
final Layout layout = widget.getLayout();
final int lineCount = layout.getLineCount();//文本有多少行
if (getBottomLine(widget) <= lineCount - 1) {//还没有到底部,则滚动到底部
Touch.scrollTo(widget, layout, widget.getScrollX(),
layout.getLineTop(lineCount) - getInnerHeight(widget));
return true;
}
return false;
}
这里我们只需要知道是否滚动到底部,所以只需要
getBottomLine(TextView widget)方法即可,但发现是private修饰,所以写一个子类继承一下,于是就有了
import android.text.Layout;
import android.text.method.MovementMethod;
import android.text.method.ScrollingMovementMethod;
import android.widget.TextView;
public class SimpleScrollingMoveMethod extends ScrollingMovementMethod {
public boolean isBottom(TextView widget){
final Layout layout = widget.getLayout();
final int lineCount = layout.getLineCount();
return getBottomLine(widget) >= lineCount - 1;
}
public boolean isTop(TextView widget){
return getTopLine(widget) == 0;
}
private int getTopLine(TextView widget) {
return widget.getLayout().getLineForVertical(widget.getScrollY());
}
private int getBottomLine(TextView widget) {
return widget.getLayout().getLineForVertical(widget.getScrollY() + getInnerHeight(widget));
}
private int getInnerHeight(TextView widget) {
return widget.getHeight() - widget.getTotalPaddingTop() - widget.getTotalPaddingBottom();
}
public static MovementMethod getInstance() {
if (sInstance == null)
sInstance = new SimpleScrollingMoveMethod();
return sInstance;
}
private static SimpleScrollingMoveMethod sInstance;
}
现在已经知道了是否滑动到底部了,接下来就是解决滑动冲突的问题了.网上还是有很多文章讲这个的,就不多说,上一段代码好了
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
public class ScrollTextView extends android.support.v7.widget.AppCompatTextView {
public ScrollTextView(Context context) {
super(context);
}
public ScrollTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setMovementMethod(SimpleScrollingMoveMethod.getInstance());
}
float mLastY;
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mLastY = event.getY();
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
float scrollY = event.getY() - mLastY;
SimpleScrollingMoveMethod movementMethod = (SimpleScrollingMoveMethod) getMovementMethod();
if (scrollY < 0 && movementMethod.isBottom(this)){
getParent().requestDisallowInterceptTouchEvent(false);
}else if (scrollY > 0 && movementMethod.isTop(this)){
getParent().requestDisallowInterceptTouchEvent(false);
}else {
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
}
return super.dispatchTouchEvent(event);
}
}
完整的调用流程截图走一下好了.
到此结束了,仅处理textView如何处理底部事件滑动冲突,至于滑动的其他处理就类似了!不过没有ScrollView丝滑,哈哈!
补充一下,ScrollView与TextView判断到底或者到顶的方式不一样,ScrollView是View高度判断,而TextView则是文字行数判断,所以还是ScrollView处理的精确一些