Android自定义View之常用工具源码分析.docx
- 文档编号:25856550
- 上传时间:2023-06-16
- 格式:DOCX
- 页数:15
- 大小:21.78KB
Android自定义View之常用工具源码分析.docx
《Android自定义View之常用工具源码分析.docx》由会员分享,可在线阅读,更多相关《Android自定义View之常用工具源码分析.docx(15页珍藏版)》请在冰豆网上搜索。
Android自定义View之常用工具源码分析
Android自定义View之常用工具源码分析
常用工具介绍
在使用自定义View的时候,常常会用到一些Android系统提供的工具。
这些工具封装了我们经常会用到的方法,比如拖拽View,计算滑动速度,View的滚动,手势处理等等。
如果我们自己去实现这些方法会比较繁琐,而且容易出一些bug。
所以,作为自定义View系列学习和教程的开端,先了解一下这些常用的工具,以便在后续的学习和工作中使用。
Configuration
ViewConfiguration
GestureDetector
VelocityTracker
Scroller
ViewDragHelper
现在这些工具都在这了,接下来就让我们来一个个分析吧
Configuration
Gogle官方文档对Configuration的描述如下:
Thisclassdescribesalldeviceconfigurationinformationthatcanimpacttheresourcestheapplicationretrieves.Thisincludesbothuser-specifiedconfigurationoptions(localelistandscaling)aswellasdeviceconfigurations(suchasinputmodes,screensizeandscreenorientation).
YoucanacquirethisobjectfromResources,usinggetConfiguration().Thus,fromanactivity,youcangetitbychainingtherequestwithgetResources():
意思是你可以通过使用getConfiguration()方法从Resources获取此对象。
因此,在一个Activity中,你可以通过用getResources()方法请求来获得它:
Configurationconfig=getResources().getConfiguration();
Configuration用来描述设备的配置信息。
比如用户的配置信息:
locale和scaling等等
比如设备的相关信息:
输入模式,屏幕大小,屏幕方向等等
我们可以通过如下方式来获取需要的相关信息:
Configurationconfiguration=getResources().getConfiguration();
//获取国家码
intcountryCode=configuration.mcc;
//获取网络码
intnetworkCode=configuration.mnc;
//判断横竖屏
if(configuration.orientation==Configuration.ORIENTATION_PORTRAIT){
}else{
}
ViewConfiguration
看完Configuration再来看看ViewConfiguration。
这两者的名字有些像,差了一个View;咋一看,还以为它们是继承关系呢,其实不然。
ContainsmethodstostandardconstantsusedintheUIfortimeouts,sizes,anddistances.
意思是包含在UI中用于超时,大小和距离的标准常量的方法。
ViewConfiguration提供了一些自定义控件用到的标准常量,比如尺寸大小,滑动距离,敏感度等等。
可以利用ViewConfiguration的静态方法获取一个实例
ViewConfigurationviewConfiguration=ViewConfiguration.get(context);
这里介绍一下ViewConfiguration的几个对象方法
ViewConfigurationviewConfiguration=ViewConfiguration.get(context);
//获取touchSlop。
该值表示系统所能识别出的被认为是滑动的最小距离
inttouchSlop=viewConfiguration.getScaledTouchSlop();
//获取Fling速度的最小值和最大值
intminimumVelocity=viewConfiguration.getScaledMinimumFlingVelocity();
intmaximumVelocity=viewConfiguration.getScaledMaximumFlingVelocity();
//判断是否有物理按键
booleanisHavePermanentMenuKey=viewConfiguration.hasPermanentMenuKey();
ViewConfiguration还提供了一些非常有用的静态方法,比如:
//双击间隔时间.在该时间内是双击,否则是单击
intdoubleTapTimeout=ViewConfiguration.getDoubleTapTimeout();
//按住状态转变为长按状态需要的时间
intlongPressTimeout=ViewConfiguration.getLongPressTimeout();
//重复按键的时间
intkeyRepeatTimeout=ViewConfiguration.getKeyRepeatTimeout();
//以毫秒为单位的持续时间,我们将等待以查看触摸事件是否是跳转点击。
如果用户在此间隔内不移动,则认为是轻敲。
intjumpTapTimeout=ViewConfiguration.getJumpTapTimeout();
GestureDetector
老规矩,先看一下Google官方文档对GestureDetector的描述
DetectsvariousgesturesandeventsusingthesuppliedMotionEvents.TheGestureDetector.OnGestureListenercallbackwillnotifyuserswhenaparticularmotioneventhasoccurred.ThisclassshouldonlybeusedwithMotionEventsreportedviatouch(don’tusefortrackballevents).Tousethisclass:
上面的大体意思是:
使用GestureDetector提供的MotionEvents检测各种手势和事件。
GestureDetector.OnGestureListener回调将在特定运事件发生时通知用户。
此类只应与通过触摸报告的MotionEvent(不用于轨迹球事件)一起使用。
要使用此类,需要完成以下几点:
CreateaninstanceoftheGestureDetectorforyourView
IntheonTouchEvent(MotionEvent)methodensureyoucallonTouchEvent(MotionEvent).Themethodsdefinedinyourcallbackwillbeexecutedwhentheeventsoccur.
IflisteningforonContextClick(MotionEvent)youmustcallonGenericMotionEvent(MotionEvent)inonGenericMotionEvent(MotionEvent).
意思是:
为您的视图创建GestureDetector的实例
在onTouchEvent(MotionEvent)方法中,确保调用onTouchEvent(MotionEvent)方法。
在回调中定义的方法将在事件发生时执行。
如果监听onContextClick(MotionEvent),则必须在onGenericMotionEvent(MotionEvent)中调用onGenericMotionEvent(MotionEvent)方法。
我们都知道,我们可以在onTouchEvent()中自己处理手势。
其实Android系统也给我们提供了一个手势处理的工具,这就是GestureDetector手势监听类。
利用GestureDetector可以简化许多操作,轻松实现一些常用的功能。
那么接下来就让我们来看一下它是如何使用的吧!
第一步:
实现OnGestureListener
privateclassGestureListenerImplimplementsGestureDetector.OnGestureListener{
//触摸屏幕时均会调用该方法
@Override
publicbooleanonDown(MotionEvente){
System.out.println("--->手势中的onDown方法");
returnfalse;
}
//手指在屏幕上拖动时会调用该方法
@Override
publicbooleanonFling(MotionEvente1,MotionEvente2,floatvelocityX,floatvelocityY){
System.out.println("--->手势中的onFling方法");
returnfalse;
}
//手指长按屏幕时均会调用该方法
@Override
publicvoidonLongPress(MotionEvente){
System.out.println("--->手势中的onLongPress方法");
}
//手指在屏幕上滚动时会调用该方法
@Override
publicbooleanonScroll(MotionEvente1,MotionEvente2,floatdistanceX,floatdistanceY){
System.out.println("--->手势中的onScroll方法");
returnfalse;
}
//手指在屏幕上按下,且未移动和松开时调用该方法
@Override
publicvoidonShowPress(MotionEvente){
System.out.println("--->手势中的onShowPress方法");
}
//轻击屏幕时调用该方法
@Override
publicbooleanonSingleTapUp(MotionEvente){
System.out.println("--->手势中的onSingleTapUp方法");
returnfalse;
}
}
第二步:
生成GestureDetector对象
GestureDetectorgestureDetector=newGestureDetector(context,newGestureListenerImpl());
这里的GestureListenerImpl就是GestureListener监听器的实现。
第三步:
将Touch事件交给GestureDetector处理
比如将Activity的Touch事件交给GestureDetector处理
@Override
publicbooleanonTouchEvent(MotionEventevent){
returnmGestureDetector.onTouchEvent(event);
}
比如将View的Touch事件交给GestureDetector处理
mButton=(Button)findViewById(R.id.button);
mButton.setOnTouchListener(newOnTouchListener(){
@Override
publicbooleanonTouch(Viewarg0,MotionEventevent){
returnmGestureDetector.onTouchEvent(event);
}
});
VelocityTracker
还是老规矩,看一下Google官方文档对VelocityTracker的描述
Helperfortrackingthevelocityoftouchevents,forimplementingflingingandothersuchgestures.Useobtain()toretrieveanewinstanceoftheclasswhenyouaregoingtobegintracking.PutthemotioneventsyoureceiveintoitwithaddMovement(MotionEvent).WhenyouwanttodeterminethevelocitycallcomputeCurrentVelocity(int)andthencallgetXVelocity(int)andgetYVelocity(int)toretrievethevelocityforeachpointerid.
大概意思就是:
这是一个帮助器,用于跟踪触摸事件的速度,用于实现拖拽和其他这样的手势。
当您要开始跟踪时,使用gets()来检索类的新实例。
使用addMovement(MotionEvent)将接收的运动事件放入其中。
当你想要确定速度调用computeCurrentVelocity(int),然后调用getXVelocity(int)和getYVelocity(int)检索每个指针id的速度。
其实这个工具一看名字,就很容易猜到意思了啊,速度追踪嘛。
VelocityTracker用于跟踪触摸屏事件(比如,Flinging及其他Gestures手势事件等)的速率。
简单说一下它的常用套路。
第一步:
开始速度追踪
privatevoidstartVelocityTracker(MotionEventevent){
if(mVelocityTracker==null){
mVelocityTracker=VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
}
在这里我们初始化VelocityTracker,并且把要追踪的MotionEvent注册到VelocityTracker的监听中。
第二步:
获取追踪到的速度
privateintgetScrollVelocity(){
//设置VelocityTracker单位.1000表示1秒时间内运动的像素
mVelocityTputeCurrentVelocity(1000);
//获取在1秒内X方向所滑动像素值
intxVelocity=(int)mVelocityTracker.getXVelocity();
returnMath.abs(xVelocity);
}
获取1秒内Y方向所滑动像素值的原理同上
第三步:
解除速度追踪
privatevoidstopVelocityTracker(){
if(mVelocityTracker!
=null){
mVelocityTracker.recycle();
mVelocityTracker=null;
}
}
Scroller
老规矩,看一下Google官方文档对Scroller的描述
Thisclassencapsulatesscrolling.Youcanusescrollers(ScrollerorOverScroller)tocollectthedatayouneedtoproduceascrollinganimation—forexample,inresponsetoaflinggesture.Scrollerstrackscrolloffsetsforyouovertime,buttheydon’tautomaticallyapplythosepositionstoyourview.
It’syourresponsibilitytogetandapplynewcoordinatesataratethatwillmakethescrollinganimationlooksmooth.
大概意思是:
这个类封装了滚动。
您可以使用滚动器(滚动器或OverScroller)来收集生成滚动动画所需的数据,例如,响应fling手势。
滚动条跟踪您的滚动偏移量,但它们不会自动应用这些位置到您的视图。
获得和应用新的坐标,将使滚动动画看起来拥有流畅的速度是你的责任。
举个例子:
privateScrollermScroller=newScroller(context);
...
publicvoidzoomIn(){
//Revertanyanimationcurrentlyinprogress
mScroller.forceFinished(true);
//Startscrollingbyprovidingastartingpointand
//theancetotravel
mScroller.startScroll(0,0,100,0);
//Invalidatetorequestaredraw
invalidate();
}
如果想要跟踪x/y坐标的更改位置,可以使用computeScrollOffset()方法。
该方法返回一个布尔值以指示滚动器是否完成。
如果不是,则意味着fling或编程泛操作仍在进行中。
你可以使用此方法查找x和y坐标的当前偏移量,例如:
if(mSputeScrollOffset()){
//Getcurrentxandypositions
intcurrX=mScroller.getCurrX();
intcurrY=mScroller.getCurrY();
...
}
相信大家对Scroller也比较熟悉,所以这里我们也不讲太多,只强调几点:
第一点:
scrollTo()和scrollBy()的关系
先看scrollBy()的源码
publicvoidscrollBy(intx,inty){
scrollTo(mScrollX+x,mScrollY+y);
}
很清晰嘛,也就是说scrollBy()方法调用了scrollTo()方法,最终起作用的是scrollTo()方法。
第二点:
scroll的本质
scrollTo()和scrollBy()移动的只是View的内容,而且View的背景是不移动的。
第三点:
scrollTo()和scrollBy()方法的坐标说明
假设我们对于一个TextView调用scrollTo(0,25);那么该TextView中的content(比如显示的文字:
Hello)会怎么移动呢?
向下移动25个单位?
不!
恰好相反!
!
这是为什么呢?
因为调用该方法会导致视图重绘,即会调用
publicvoidinvalidate(intl,intt,intr,intb)
此处的l,t,r,b四个参数表示View原来的坐标
在该方法中最终会调用:
tmpr.set(l-scrollX,t-scrollY,r-scrollX,b-scrollY);
p.invalidateChild(this,tmpr);
其中tmpr是一个Rect,this是原来的View;通过这两行代码就把View在一个Rect中重绘。
请注意第一行代码:
原来的l和r均减去了scrollX
原来的t和b均减去了scrollY
也就是说scrollX如果是正值,那么重绘后的View的宽度反而减少了;反之同理
也就是说scrollY如果是正值,那么重绘后的View的高度反而减少了;反之同理
所以,TextView调用scrollTo(0,25)和我们的理解相反
scrollBy(intx,inty)方法与上类似,不再多说了.
ViewDragHelper
老规矩,看一下Google官方文档对ViewDragHelper的描述
ViewDragHelperisautilityclassforwritingcustomViewGroups.ItoffersanumberofusefuloperationsandstatetrackingforallowingausertodragandrepositionviewswithintheirparentViewGroup.
大概意思是:
ViewDragHelper是一个用于编写自定义ViewGroups的实用程序类。
它提供了许多有用的操作和状态跟踪,以允许用户在其父ViewGroup中拖动和重新定位视图。
在项目中很多场景需要用户手指拖动其内部的某个View,此时就需要在onInterceptTouchEvent()和onTouchEvent()这两个方法中写不少逻辑了,比如处理:
拖拽移动,越界,多手指的按下,加速度检测等等。
ViewDragHelper可以极大的帮我们简化类似的处理,它提供了一系列用于处理用户拖拽子View的辅助方法和与其相关的状态记录。
比较常见的:
QQ侧滑菜单,NavigationDrawer的边缘滑动,都可以由它实现。
ViewDragHelper的使用并不复杂,在此通过一个示例展示其常用的用法。
publicclassMyLinearLayoutextendsLinearLayout{
privateViewDragHelpermViewDragHelper;
publicMyLinearLayout(Contextcontext,AttributeSetattrs){
super(context,attrs);
initViewDragHelper();
}
//初始化ViewDragHelper
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android 自定义 View 常用工具 源码 分析