自定义View学习笔记(一)

View 是Android 所有控件的基类,textview等都继承view,而LinearLayout,它继承ViewGroup
需要注意的是ViewGroup也继承View。
(1)Android 坐标系(绝对坐标)
在Android 中,将屏幕左上角的顶点作为Android坐标系的原点,这个原点向右是x轴的正方向,向下是y轴的正方向(在触控事件中,使用getRawX() 和 getRawY()方法获得的坐标也是Android坐标系的坐标
(2)View坐标系
在这里插入图片描述
(2.1)View获取自身的宽和高
width = getRight() - getLeft();
height = getBottom() - getTop();
当然这样作有些麻烦,系统已经向我们提供了获取view宽和高的方法。getHeight() 和getWidth(),源码和上述方法是一致的
(2.2)View 自身的坐标
通过如下方法可以获得到其父控件(viewGroup)的距离
getTop() :获取view自身顶边到父控件ViewGroup的距离
getLeft():获取view自身左边到其父控件viewGroup的距离
getRight() :view 自身右边…
getBottom() :view自身下边…

(2.3)MotionEvent 提供的方法
如上图中的原点,假设就是我们的触摸点,最终都是由onTouchEvent(MotionEvent ev)方法来处理
MotionEvent 在用户交互中作用最大,其内部提供了很多的常量,比如我们常用的ACTION_DOWN,ACTION_MOVE , ACTION_UP,此外,MotionEvent还提供了获取焦点坐标的各种方法
getX() :获取点击事件距离控件左边的距离,视图坐标
getY():获取点击事件距离控件顶边的距离,视图坐标
getRawX() :获取点击事件距离整个屏幕左边的距离,绝对坐标
getRawY() :获取点击事件距离整个屏幕右边的距离,绝对坐标

(3)view的滑动
不管是哪种滑动方式,其基本思想都是类似的,当点击事件传到View时,系统记下触摸点的坐标,手指移动时系统记下系统后触摸的坐标并计算出偏移量,并通过偏移量来修改view的坐标
实现View的滑动有很多方式:
(3.1)layout()方法
View 进行绘制的时候会调用onLayout()方法,设置显示的位置

@Override
public boolean onTouchEvent(MotionEvent event) {
    int x = (int)event.getX();
        int y = (int)event.getY();
       switch (event.getAction()){
           case MotionEvent.ACTION_DOWN:
                lastX = (int)event.getX();            lastY = (int)event.getY();
                Log.d(TAG, "onTouchEvent--------------> ACTION_DOWN");
                break;        
                case MotionEvent.ACTION_MOVE:            int offSetX = x - lastX;            
                int offSetY = y - lastY;
                layout(getLeft() + offSetX,getTop()+offSetY,getRight() + offSetX,getBottom()+offSetY);            
                Log.d(TAG, "onTouchEvent--------------> ACTION_MOVE" + offSetY + "\n" + offSetX);            
                break;
                case MotionEvent.ACTION_UP:           
                Log.d(TAG, "onTouchEvent--------------> ACTION_UP");          
                break;       
                default:            
                break;    
}

(3.2)offsetLeftAndRight() 与 offsetTopAndBottom()
这两种方法和layout方法差不多,将ACTION_MOVE中的代码替换为

case MotionEvent.ACTION_MOVE:    
int offSetX = x - lastX;    
int offSetY = y = lastY; 
offsetLeftAndRight(offSetX);
offsetTopAndBottom(offSetY);

(3.3)LayoutParams()改变布局参数
LayoutParams主要保存了一个View的布局参数,因此我们可以通过LayoutParams来改变view的布局参数从而达到改变view的位置的效果,将ACTION_MOVE中的代码替换为

case MotionEvent.ACTION_MOVE:    
int offSetX = x - lastX;  
int offSetY = y - lastY;
RelativeLayout.LayoutParams layoutParams =(RelativeLayout.LayoutParams) getLayoutParams();   
layoutParams.leftMargin = getLeft() + offSetX;   
layoutParams.topMargin = getTop() + offSetY;   
setLayoutParams(layoutParams);    
Log.d(TAG, "onTouchEvent--------------> ACTION_MOVE" + offSetY + "\n" + offSetX);    
break;

注意:因为父控件是RelativeLayout所以使用RelativeLayout.LayoutParams,如果是LinearLayout,则使用的是LinearLayout.LayoutParams
(3.4)scrollTo 与scrollBy
scrollTo(x , y)表示移动到一个具体的坐标点,而scrollBy(dx ,dy)则表示移动的增量为dx ,dy
其中,scrollBy最终还是会调用scrollTo的
scrollBy 和 scrollTo 移动的是view中的内容,如果是在viewGroup中使用的话,则是移动其所有的子view

下面改变ACTION_MOVE中的代码

((View)getParent()).scrollBy(-offSetX,-offSetY);

注意:
如果实现随手移动的效果,则需要设置为负值,原因为:参考对象不同,负数为正方向

(3.5)Scroller 来实现过渡效果的滑动,这个过程不是瞬间完成的,而是在一定时间间隔内完成的。Scroller本身不能实现View的滑动,它需要与View的computeScroll()方法配合使用才能实现弹性滑动的效果。
a>初始化Scroller对象

public CustomTextView(Context context, @Nullable AttributeSet attrs) {   
super(context, attrs);    
mScroller = new Scroller(context);
}

b>接下来重写computeScroll()方法,系统会在绘制View 的时候在draw()方法中调用该方法,在这个方法中,我们调用scrollTo()方法并通过scroller来不断获取当前的滚动值,每滑动一段距离,就调用invalidate()方法不断地进行重绘,重绘就会调用computeScroll()方法,这样通过不断地移动一个小的距离并连贯起来实现了平滑移动的效果

@Override
public void computeScroll() {  
super.computeScroll();
if(mScroller.computeScrollOffset()){        
((View)getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());      
invalidate();   
}
}
public void start(){    
mScroller.startScroll(0,0,-400,0,1000);   
invalidate();
}

mScroller.getCurrX() //获取mScroller当前水平滚动的位置
mScroller.getCurrY() //获取mScroller当前竖直滚动的位置
mScroller.getFinalX() //获取mScroller最终停止的水平位置
mScroller.getFinalY() //获取mScroller最终停止的竖直位置
//滚动,startX, startY为开始滚动的位置,dx,dy为滚动的偏移量, duration为完成滚动的时间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值