




下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
一、定义控件基础拖动控件了解andoridView自定义View加载阶段//View的绘制流程1,ViewViewpublicclassMyViewextendsView}this(context,null);}//当需要将自定义View在xml文件中使用的时候需要重写这个构造方this(context,attrs,0);}//当需要将自定义View在xml文件中,并且当前控件需要自定义样式的时候.publicCanvasTestView(Contextcontext,AttributeSetattrs,intdefStyleAttr){super(context,attrs,defStyleAttr);}Canvasapi:Paint(Paint//定义一个点,xyPointFpoint=newPointF(x,//////1,2:x,y//3,4:x,y//4:矩形的下边相对于屏幕上边缘的距离RectFrect=newRectF(l,t,r,b);//canvas.drawArc(rect,,false,////1,2:x,y//x,yfloat[]pts={x1,y1,x2,y2,//2:pts集合中的哪个元素开始绘制(从哪里开始,x坐标,y坐标,此类推//3:ptscanvas的变换处理:Android中的坐标系:默认是以屏幕左上角为原点,x方向向右为+,ycanvastranslaterotate方法相当于对坐标系进行了平移和旋转,基于旋转后的Path//绘制曲//1,2:x,y//3,4:x,y绘制文//2,3:xy//////////xCanvas的其他处综合案例-publicclassPieDataEntity{privateStringname;privatefloatvalue;privateintcolor;privateint[]mColors={0xFFCCFF00,0xFF6495ED,0xFFE32636,0xFF800000,0xFF808000,0xFFFF8C69,0xFF808080,mRectF=newRectF();mPaint=neint();mLinePaint=nemTextPaint=neint();mPath=neth();}protectedvoidonSizeChanged(intw,inth,intoldw,intoldh){super.onSizeChanged(w,h,oldw,oldh);mTotalWidth=w;mTotalHeight=h;mRectF.left=-mRadius;mRectF.top=-mRadius;mRectF.right=mRadius;}if(mDataList==//floatstartAngle=for(inti=0;i<mDataList.size();i++)//// //重置路径:为了下次再绘制不会和上一次floatstartLineX=(float)(mRadius*Math.cos(Math.toRadians(startAngle+sweepAnglefloatstartLineY=(float)(mRadius*Math.sin(Math.toRadians(startAngle+sweepAnglefloatendLineX=(float)((mRadius+30)*Math.cos(Math.toRadians(startAngle+sweepAngle/2)));floatendLineY=(float)((mRadius+30)*Math.sin(Math.toRadians(startAngle+/startAngle+=sweepAngle+1;floatres=mDataList.get(i).getValue()/mTotalValue*100;floatv=startAngle%//判断如果起始角度>90270if(startAngle%360.0>=90.0&&startAngle%360.0<=270.0){Log.i("test","resToRound:"+resToRound);canvas.drawText(resToRound+"%",endLineX-mTextPaint.measureText(resToRound+"%"),endLineY,mTextPaint);}else}}自定义ViewGrouponLayout方法介ViewGroup需要继承ViewGroup,除了需要重写构造方法之外,onLayout方法:1,onLayout方法就是主要为了摆放ViewGroup的子视图protectedvoidonLayout(booleanchanged,intl,intt,intr,intb)intchildCount=for(inti=0;i<childCount;i++)Viewchild=}inttop=0;intchildIndex=for(inti=2;i>=0;i--)for(intj=0;j<=i;j++)Viewchild=child.layout(30*j,top,30*(j+1),top+30);}top+=}}综合案例:privateString[]mItemTexts=newString[]{"安全中心","特色服务","投资","转账汇款","账户",""};privateint[]mItemImgs=newint[]{R.drawable.home_mbank_6_normal};<LinearLayoutxmlns:android="http://s for(inti=0;i<resIds.length;i++)Viewview= _item,
ImageViewiv=(ImageView)TextViewtv=(TextView)view//view}}publicclassMainActivityextends ptivity{privateCircleLayoutmCircle privateString[]texts=newString[]{"安全中心","特色服务","投资","转账汇款","账户",""};privateint[]imgs=newint[]{R.drawable.home_mbank_6_normal};{mCircleLayout.setItemIconsAndTexts(imgs,texts);}}protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){super.onMeasure(widthMeasureSpec,heightMeasureSpec);forinti0igetChildCounti++)}}privateintd=480;protectedvoidonLayout(booleanchanged,intl,intt,intr,intb){floatlayoutRadius=d/2f;finalintchildCount=getChildCount();intleft,top; itemintcWidth=//floatangleDelay=360///for(inti=0;i<childCount;i++){finalViewchild=getChildAt(i);//360取余数,0-360mStartAngle%=//floattmp=layoutRadius-cWidth/left=(int) Math.cos(Math.toRadians(mStartAngle))-1///lefttop=(int)( Math.sin(Math.toRadians(mStartAngle))-1/child.layout(left,top,left+cWidth,top+//mStartAngle+=}}自定义控件之onMeasure方法的处ViewGroup,默认只会测量自身控件MeasureSpec32int值mode分为三种3,AT_MOST:2<<30至多为多少,例如WRAP_CONTENT,若控件本身没有默认尺寸,则系统会尽可能的把空间赋予控件,为MATCH_PARENTMeasureSpecspec= MeasureSpec.getSize(measureSpec);MeasureSpecsize优化圆形菜MeasureSpecsizemodemodeMeasureSpec.EXACTLY②用户宽输入固定mode③用户宽输入wrap_content,由于无法确定控件宽高,则直接取屏幕宽度和高度的较小值 对孩子视图进for(inti=0;i<getChildCount();i++)}intmeasureWidth;int//判断模式主要处理两种:1,2,intmode=MeasureSpec.getMode(widthMeasureSpec);intsize=MeasureSpec.getSize(widthMeasureSpec);////指定内容是的背景WRAP_CONTENT设定为背景,即:背景多大,控件就多大intsuggestedMinimumWidth=//suggestedMinimumWidth0,则无背景if(suggestedMinimumWidth==0){measureWidth=measureHeight=}else }}elsemeasureWidth=measureHeight=Math.min(size,}setMeasuredDimension(measureWidth,measureHeight);for(inti=0;i<getChildCount();i++){Viewchild=//默认系统是可以通过onMeasureMeasureSpec参数的,而对于inflate进来的子视图MeasureSpec参数的//故:需要我们自己设计child.measure(makeMeasureSpec,makeMeasureSpec);}饼状图的点击效onTouchEvent,实现触摸事件publicbooleanonTouchEvent(MotionEventevent){switch(event.getAction()){casecasecase}return}可以通过MotionEventpublicbooleanonTouchEvent(MotionEventevent){switch(event.getAction()){case//xx//yfloatx=event.getX()-(mTotalWidth/2);floaty=event.getY()-floattouchAngle=0;if //2touchAngle+=}elseif //1touchAngle+=}elseif //3touchAngle+=}//180/π,//Math.atan(y/x)xif(touchAngle<0){touchAngle=}floattouchRadius=(float)Math.sqrt(y*y+x*x);if(touchRadius<mRadius){//未找到则返回-(和要搜索的值附近的大于搜索值对应的正确值的索引//举例//在数组//2,positionArrays.binarySearch(angles,(touchAngle))-1;}}return}*点击publicvoidsetOnItemPieClickListener(OnPieItemClickListeneronPieItemClickListener){mOnPieItemClickListener=onPieItemClickListener;}//activitypieChart.setOnPieItemClickListener(newPieChart.OnPieItemClickListener(){publicvoidonClick(intposition)}}mRectFTouch.left=-mRadius-16;mRectFTouch.top=-mRadius-16;mRectFTouch.right=mRadius+16;privatevoiddrawPie(Canvascanvas){for(inti=0;i<mDataList.size();i++){}else}}}publicbooleanonTouchEvent(MotionEventevent){switch(event.getAction()){caseif(touchRadius<}}return}privatefloatlastX;privatefloatpublicbooleanonTouchEvent(MotionEventevent){floatx=event.getX();floaty=caseMotionEvent.ACTION_DOWN:lastX=x;lastY=y;caseMotionEvent.ACTION_MOVE:floatstart=CircleUtil.getAngle(lastX,lastY,d);floatend=CircleUtil.getAngle(x,y,d);floatif(CircleUtil.getQuadrant(x,y,d)==1||CircleUtil.getQuadrant(x,y,d)==4){angle=end-start;}elseangle=start-}startAngle+=angle;lastX=x;lastY=caseMotionEvent.ACTION_UP:}//returntrue表示当前控件想要处理事件如果没有其他控件想要处理则所有的MotionEvent事件都会交给自己处理return}步骤}publicSettingItemView(Contextcontext,AttributeSetset){super(context,set);//view//2inflateviewthis}将自定义组合控件作为一个整体看,想要改变自定义控件的Textview的文本做为调用者只能给自定义组合控件传递属性值,需求是改变自定义控件的TextView的文TextView①在 <!--title内容,这里的属性名可随意定义,但最好不要定义和现有属性一致的名称-->②在activity_main.xml文件中定义名称空间和属 >③在自定义组合控件获取自定义属性的值,并设置到的TextViewpublicSettingItemView(Contextcontext,AttributeSetset){super(context,set);//view//自定的属Stringtitle=}<!--<attr<enumname="first"value="0"<enumname="middle"value="1"<enumname="last"value="2"}activity_main.xmlpublicSettingItemView(Contextcontext,AttributeSetset){super(context,set);//设置背景switch(bkg){casecase}publicvoidsetToggleOn(booleanonthis.isToggleOn=on;if(on){}else}}//publicvoidtoggle()}publicvoidonClick(Viewv){}}2,测量--->onMeasure方法二、自定义控件高级应用(带领学员分析气泡效果的处理基本效果实privatevoidinit()paint=ne }//privatefloat//privatefloatprivatePointF[]stablePoints=newPointF[]{newPointF(200f,300f),newprivatePointF[]dragPoints=newPointF[]{newPointF(100f,300f),new//12//23//34原来的固定圆和拖拽圆的附着点,控制点都是自己设置的,并不能适配到两个圆上,故要根据doublelineK=0;iflineK=}//controlPointGeometryUtil.getMiddlePoint(stableCenterdragCenter);publicbooleanonTouchEvent(MotionEventevent){switch(event.getAction()){ //xyfloatrawX=event.getRawX();floatrawY= rawX=event.getRawX();rawY=event.getRawY();}returntrue;}出现bug1:上一次绘制的界面没有销毁,需要在onDraw方法中每次绘制完路径后,加入path.reset()方法来重置路径,使得上一次绘制的路径}privateintgetStatusBarHeight(Viewview){Rectrect=newRect();returnrect.top;}protectedvoidonSizeChanged(intw,inth,intoldw,intoldh){super.onSizeChanged(w,h,oldw,oldh);statusBarHeight=}}4,粘性控件的和重privatefloat if(distance>maxDistance){}onDraw方法里判断,isOutOfRangetrue,则不绘制中间图形,相当于让中间图形if(!isOutOfRange){ //}// if(isOutOfRange){}finalPointFoldDragCenterPoint=newPointF(dragCenter.x,dragCenter.y);ValueAnimatorvalueAnimator=ValueAnimator.ofFloat(distance,0); istener(newValueAnimator.AnimatorUpda istener(){floatpercent=PointFnewPointF=}valueAnimator.setInterpolator(newOvershootInterpolator(2));}if(!isDisappear)if(!isOutOfRange)}}}如图看到的红色圆形控件为TextView①导入依赖:RecyclerViewBaseRecyclerViewAdapterHelper库appbuild.gradle文件中compile'com.}projectbuild.gradleallprojectsmaven{url "}} <!--RecyclerView--<LinearLayoutxmlns:android="http://s ><!--TextView加入一个圆形背景,原因:RecyclerView的条目显示区域仅仅有一块,而GooView的显示区域需要整个屏幕,如果直接将GooView放在条目中,拖动后会影响GooView的显示,故:使用TextView来显示,GooView后期动态加入--><shape <solidprotectedvoidonCreate(BundlesavedInstanceState){List<Msg>msgList=newArrayList<>();for(inti=0;i<50;i++)}RecyclerViewrlv=(RecyclerView)findViewById(R.id.rlv);rlv.setAdapter(newMsgAdapter(msgList));}//publicclassMsgAdapterextendsAdapter<MsgAdapter.MyViewHolder>{ ist<Msg>msgList;publicMsgAdapter(List<Msg>msgList){this.msgList=msgList;} returnnew}publicvoidonBindViewHolder(MyViewHolderholder,intposition){intunReadMsgCount=msgList.get(position).unReadMsgCount;if(unReadMsgCount==0){}else}}publicintgetItemCount()return}publicstaticclassMyViewHolderextendsRecyclerView.ViewHolder{publicTextViewtv_title;publicMyViewHolder(ViewitemView){}}}加入RecyclerView后的事件分发问题(事件分发机制1,GooView后的处理GooView当松开手后,将GooView移除,TextView①GooViewGooViewGooViewprivateStringGooViewText=gooViewText;}protectedvoidonDraw(Canvascanvas){if(!isDisappear){if }//}}paint.getTextBounds(GooViewText,0,GooViewText.length(),rect);inttextWidth=rect.width();inttextHeight=rect.height();xx坐标-文本宽度/2yy坐标+文本宽度/2float}GooViewpublicGooViewinitGooViewPosition(floatrawX,floatrawY){stableCenter.set(rawX,rawY);returnthis;}}privateContextcontext;privateGooViewthis.context=context;gooView=new //GooViewparams=new//GooView的宽高为}privateView事件交给MotionEvent//当按下去的对TextViewif(event.getAction()==MotionEvent.ACTION_DOWN){msg=(Msg)v.getTag();//隐藏mView=v;//x,yfloatrawX=event.getRawX();floatrawY=}returntrue;}}bug1:TextView然后向上移动,GooView不懂,RecyclerView动事件被RecyclerView了,需要请求RecyclerView不要事件不要事原因:利用WindowManger,不能直接移除,但,作为OnShowGooViewTouchListener并不知道什么时候该移除GooView,故:使用接口回调来////的回publicvoidpublicvoidreset();}privateOnGooViewChangedListeneronGooViewChangedListener;publicvoidsetOnGooViewChangedListener(OnGooViewChangedListeneronGooViewChangedListener){this.onGooViewChangedListener=onGooViewChangedListener;}当的时候调用的回调方法caseif(isOutOfRange)if(distance>maxDistance)if(onGooViewChangedListener!=null){}}elseif(onGooViewChangedListener!=null){}}}elseif(onGooViewChangedListener!=null){}}}在OnShowGooViewTouchListener中设置,并实现两个回调方法GooView.OnGooViewChangedListener{}//当GooView的时候,从WindowManager中移publicvoiddisappear()if(gooView.getParent()!=null){if(msg!=null){msg.unReadMsgCount=}}}//GooView重置的时候,将GooViewWindowManagerpublicvoidreset()}//}}publicViewgetSelfHeaderView(){if(selfHeaderView==null){ //selfHeaderViewWholeHeaderView中,}return}intselfHeaderViewHeight=selfHeaderView.getMeasuredHeight();returnselfHeaderViewHeight;}wholeHeaderView=new//相当于在 文件中定义一个线性布局,布局宽高}ViewselfHeaderView=intselfHeaderViewHeight= ddingTop=-selfHeaderViewHeight; wholeHeaderView.setPadding(0,minWholeHeaderVie ddingTop,0,0);}publicbooleanonTouchEvent(MotionEventevent){switch(event.getAction()){caseMotionEvent.ACTION_DOWN:downY=(int)event.getY();returncase//moveif(handleActionMove(event)){returntrue;}caseif(handleActionUp(event)){returntrue;}}return}//枚举publicenumRefreshStatus{}if(currentStatus==RefreshStatus.REFRESHING){returnfalse;}//当前控件直接进入move状态,由于当前控件的onTouchEvent的down事件未执行,downY0//movedownYif(downY==0)downY=(int)}intmoveY=(int)event.getY();intdY=moveY-downY; Log.i("test","dY:"+dY+",moveY:"+moveY+",downY:"+if(dY>0){intpaddingTop=(int)(dY/dragRadio+minWholeHeaderVieddingTop);if(paddingTop<0){//判断如果不是下拉刷新,则将状态改为下拉刷新,if语句,if(currentStatus!=RefreshStatus.PULL_DOWN){currentStatus=RefreshStatus.PULL_DOWN;} Log.i("test","scale:"+scale);}elseif(paddingTop>=0&¤tStatus!=RefreshStatus.RELEASE_REFRESH){currentStatus=RefreshStatus.RELEASE_REFRESH;}//判断如果paddingtop>maxWholeHeaderVie paddingTop=Math.min(paddingTop,maxWholeHeaderVie wholeHeaderView.setPadding(0,paddingTop,0,0);return}return}casecasecasecase}}privatebooleanhandleActionUp(MotionEventevent){downY=0;==currentStatus=}elseif(currentStatus==RefreshStatus.RELEASE_REFRESH){}}//3,paddingTop0privatevoidbeginRefreshing(){currentStatus=RefreshStatus.REFRESHING;if(listener!=null)}}publicvoidendRefreshing()currentStatus=RefreshStatus.IDLE;}//隐藏头部视图:ValueAnimator进行值改变,wholeHeaderView istener(newValueAnimator.AnimatorUpda istener(){wholeHeaderView.setPadding(0,currentPaddingTop,0,0);}}protectedvoidonFinishInflate(){ViewcontentView=}elseif(contentViewinstanceofScrollView){this.scrollView=(ScrollView)contentView;}}由于RecyclerView默认处理触摸事件,而在下拉的状况下,需要将事件不让publicbooleanonInterceptTouchEvent(MotionEventev){switch(ev.getAction()){caseMotionEvent.ACTION_DOWN:interceptDownX=ev.getX();casefloatdY=ev.getY()-//1,y方向的变化:y方向的变化量>x//2,yif(dY>0&&handleRefresh()){returntrue;}}caseMotionEvent.ACTION_UP:}return}protectedvoidonFinishInflate(){ViewcontentView=}elseif(contentViewinstanceofScrollView){this.scrollView=(ScrollView)contentView;}}returntrue;}returntrue;}return}由于down事件被RecyclerView消费掉,当RefreshLayout拿到事件已经变为move了,故:downY无法获取到值,handleActionMovedownY继续赋值if(downY==0)downY=(int)}}2,第一次滑动后抬起,down的位置向上偏移,此时向下滑动,一段距离没有任何反应,down的位置才有效果原因:由于第二次滑动时,downYdownY造成up,downYprivatebooleanhandleActionUp(MotionEventevent){downY=0;}下拉刷新的改造(美团下拉刷新 classSelfHeaderViewManager{protectedContextcontext;protectedView ViewgetSelfHeaderView();publicintgetSelfHeaderViewHeight(){intselfHeaderViewHeight=selfHeaderView.getMeasuredHeight();returnselfHeaderViewHeight;}//idle void//状态变为PullDown void void void// void// }SelfHeaderViewManagerNormalSelfHeaderViewManagerpublicclassNormalSelfHeaderViewManagerextendsSelfHeaderViewManager{privateRotateAnimationupAnimation;privateRotateAnimationdownAnimation;privateImageViewivArrow;privateImageViewthis.context=context;}//绕着的中心点逆时针旋upAnimation=newRotateAnimation(0,-180,RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF,0.5f);downAnimation=newRotateAnimation(-180,0,RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF,0.5f);}publicViewgetSelfHeaderView(){if(selfHeaderView==null){selfHeaderView=View.inflate(context, ivAnimationDrawable=(AnimationDrawable)ivAnimation.getDrawable();}return}intselfHeaderViewHeight=selfHeaderView.getMeasuredHeight();returnselfHeaderViewHeight;}}publicvoidchangeToPullDown(){}publicvoidchangeToReleaseRefresh}publicvoidchangeToRefreshing}publicvoidendRefreshing()}publicvoidhandleScale(floatscale)}}publicvoidchangeToIdle(){}}}}}}publicvoidendRefreshing()}if(dY>0)if(paddingTop<0)}elseif(paddingTop>=0&¤tStatus!=RefreshStatus.RELEASE_REFRESH)}}}publicvoidhandleScale(floatscale){}三、作MainActivityintwinWidth=outMetrics.
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 智能停车场 系统
- 片区开发项目可行性研究报告
- 低空经济的未来发展前景
- 农业保险精准赔付系统实施方案
- 物流配送形式
- 茶艺师练习试题附答案(一)
- 妇产科护理复习试题及答案
- 电商平台订单管理和物流配送优化方案
- 绿色建筑节能技术应用案例分享
- 国际贸易谈判实务作业指导书
- 2023年陕西高职单招考试语文真题
- 石油焦生产工艺及设备解读课件
- 肺炎-疑难病例讨论课件
- 2023全国高中化学奥林匹克竞赛预赛试题及答案
- 音乐剧悲惨世界歌词
- 复合材料铺层设计说明
- 戴德梁行物业培训ppt课件
- GB∕T 16422.3-2022 塑料 实验室光源暴露试验方法 第3部分:荧光紫外灯
- 煤矿防治水中长期规划2017—2019
- 2022年乡镇(街道)执法人员资格考试题库(含答案)
- 新版广西大学毕业设计封面
评论
0/150
提交评论