在分析Magic源码的时候,深受启发,发现了很多有用的点,要一步一步的剖析才能理解的更深,这里就在title的下滑线的基础上进行详细分析,
一、 基于HorizontalScrollView可以滚动的TextView
我们定义一个LinearLayout,然后在LinearLayou中添加自定义的TextView,这时我们会发现,它并不能滚动,只是显示为了一行,代码和效果如下,在这里是循环了10次,添加了10个textview,并且要求textview是单行的和缩略的。
for(int i=0;i<10;i++){
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT
);
TextView textView =new TextView(this);
textView.setText("文字测试"+i);
lp.weight=i;
textView.setLayoutParams(lp);
textView.setSingleLine();
textView.setEllipsize(TextUtils.TruncateAt.END);
ll_title.addView(textView);
}
在手机上显示的效果如下,可以看得到这个textview并不是滚动的,而是铺满屏幕的。
这时候我们只用在布局上使用HorizontalScrollView,包裹住我们的LinearLayout即可实现LinearLayout的滚动,这是一个非常简单的基础点。效果如下图,可以看到明显的下划线,是可以滚动的,并且文字的也可以显示完整了。
二、绘制一条可以滑动的线
2.1 首先我们要在屏幕绘制一条粗线条,这个可以在onDraw方法中实现,我们定义一个RectF,定义他的上下左右四个边距,然后再定义画笔和就可以实现了,代码如下
private void init(){
paint.setColor(Color.BLUE);
rectF.left=30;
rectF.right=60;
rectF.top=90;
rectF.bottom=120;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawRoundRect(rectF,8,8,paint);
}
2.2 实现线的水平滑动,这主要是利用重绘的原理实现的,我们需要不断的修改线的left和right的值,来实现滚动
,这其实是一个难点,这里只是提一下,后面会当做难点来讲解,因为这里涉及到了偏移量的问题,还有回调效果。这两个难点,是需要计算。
//移动到固定位置
rectF.left=30;
rectF.right=60;
三、实现所画的线随着ViewPager的滑动而滑动
1.1 在这里使用的ViewPager为基础来实现的,在这里也要介绍一下ViewPager的OnPageScrolled方法,在这里主要就是利用了positionOffset来实现,这是一个ViewPager的偏移量,是一个小于1的小数。
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
//position表示滚动的位置
//positionOffset表示滚动的偏移量,这个是重点
//positionOffsetPixels 表示偏移的像素
}
我们要控制线滑动的边距和速度,在这里使用rectF.left控制移动,用getInterpolation控制速度,当向右移动的距离超过屏幕的宽度时则停止移动。
虽然是控制rectF.left来实现移动,但是这个移动的位置应该事先确定好,这样子,才能移动到想要移动的位置,所以
rectF.left=rectF.left+(50)*mStartInterpolator.getInterpolation(positionOffset);
rectF.right= rectF.right+50*mEndInterpolator.getInterpolation(positionOffset);
这种写法是不对的,recfF.left应该换成固定的坐标,具体的写法如下,这样子就实现了线的平滑移动。
rectF.left =100 + 500*mStartInterpolator.getInterpolation(v);
rectF.right = 130 +500* mEndInterpolator.getInterpolation(v);
四、实现所画的线随着HorizontalScrollView的滑动而滑动
这个实现的原理,主要是利用了HorizontalScrollView的onScrollChanged方法
首先我们自定义HorizontalScrollView
public class MyHorizontalScrollView extends HorizontalScrollView {
public interface ScrollViewListener {
void onScrollChanged(HorizontalScrollView scrollView, int x, int y, int oldx, int oldy);
}
private ScrollViewListener scrollViewListener = null;
public MyHorizontalScrollView(Context context) {
super(context);
}
public MyHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void setScrollViewListener(ScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
@Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
}
}
}
定义一个新的线可以滑动的线的控件
public class ScrollLineIndicator extends View {
RectF rectF =new RectF();
Paint mPaint;
public ScrollLineIndicator(Context context) {
super(context);
}
public ScrollLineIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ScrollLineIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public ScrollLineIndicator(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
rectF.left=50;
rectF.right=100;
rectF.top=50;
rectF.bottom=100;
mPaint=new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRoundRect(rectF,0,0,mPaint);
}
public void onScrollChanged(int x, int y, int oldx, int oldy) {
rectF.left=x;
rectF.right=x+50;
invalidate();
}
实现滚动
scrollView.setScrollViewListener(new MyHorizontalScrollView.ScrollViewListener() {
@Override
public void onScrollChanged(HorizontalScrollView scrollView, int x, int y, int oldx, int oldy) {
scrollLineIndicator.onScrollChanged(x,y,oldx,oldy);
}
});
效果图如下: