重写Android ----View与ViewGroup
重写View与ViewGroup
相关资料:
http://www.gcssloop.com/customview/CustomViewIndex/
https://www.cnblogs.com/Jaylong/p/viewgroup.html
https://www.jianshu.com/p/138b98095778
https://github.com/GcsSloop/AndroidNote/issues/7
(Android 2D操作是要关闭其硬件加速)
1.先说下View与ViewGroup的认识:
View:我们可以看做一个个展示界面的对象。而ViewGroup就是装View的容器。
所以我们在重写View与ViewGroup的侧重点会有不同。
View侧重于onDraw(),对自己的长宽测量与设置onMeasure(),绘制。
而ViewGroup侧重于对自己长宽设置,在onMeasure()中setMeasureDimension(w,h),与它们的排放位子onLayout()。
2.一步步的实践。
上部
重写View的结果图:
准备:
a.为实验提供数据的,第一个name为numbers的为扇形提供百分比的。第二个是每个扇形的名字。
b.R.id.review
c.扇形对象类sector
d.MainActivity
e.重写View的类review
package com.example.reView; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Shader; import android.util.AttributeSet; import android.util.Log; import android.view.View; import com.example.hi.study.R; import java.util.Arrays; import java.util.List; /** * Created by hi on 1/15/2018. */ public class reView extends View { String mtitle; int number; Paint mPaint; int mWidth; int mHeiht; List<sector> sectors; List<Integer> COL= Arrays.asList(Color.BLUE,Color.YELLOW,Color.GREEN,Color.GRAY,Color.DKGRAY); float StartAngle=0; float currentAngle=0; OnClickListener mListener; public reView(Context context) { this(context,null); } public reView(Context context, AttributeSet attrs) { this(context,attrs,0); } public reView(final Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.reView); mtitle=ta.getString(R.styleable.reView_titles); number=ta.getInteger(R.styleable.reView_numbers,0); ta.recycle(); // this.setOnClickListener(new OnClickListener() { // @Override // public void onClick(View v) { // Toast.makeText(context,"内部监听事件被点击",Toast.LENGTH_LONG).show(); // } // }); } private void init() { mPaint=new Paint(); mPaint.setStyle(Paint.Style.FILL); mPaint.setAntiAlias(true); } public void setSector(List<sector> list){ sectors=list; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mHeiht=h; mWidth=w; init(); } // @Override // public boolean onTouchEvent(MotionEvent event) { // mListener.onClick(this); // return true; // } // @Override // public void setOnClickListener(OnClickListener l) { // mListener=l; // } @Override protected void onDraw(Canvas canvas) { if (sectors==null){ Log.i("sec","sectors is null"); return; } Log.i("info--sectors.size",""+sectors.size()); canvas.translate(mWidth/2,mHeiht/3); int len=mHeiht>mWidth?mWidth:mHeiht; int r= (int) ((len/2)*0.8); RectF rect=new RectF(-r,-r,r,r); for (int i=0;i<sectors.size();i++){ currentAngle=((float) sectors.get(i).getTime()/1000)*360; mPaint.setColor(COL.get(i)); canvas.drawArc(rect,StartAngle, currentAngle, true, mPaint); canvas.save(); canvas.rotate(StartAngle+currentAngle/2); mPaint.setColor(Color.BLACK); mPaint.setStrokeWidth(2); canvas.drawLine(r,0,r+50,0,mPaint); mPaint.setTextSize(25); canvas.drawText(sectors.get(i).getWeight()+"%",r/2,0,mPaint); canvas.drawText(sectors.get(i).getTitle(),r+80,0,mPaint); canvas.restore(); StartAngle=StartAngle+currentAngle; } canvas.translate(0,r+200); mPaint.setTextSize(50); LinearGradient ml=new LinearGradient(0-mPaint.measureText(mtitle)/2,0,0+mPaint.measureText(mtitle)/2,0,Color.YELLOW,Color.BLUE, Shader.TileMode.CLAMP); mPaint.setShader(ml); canvas.drawText(mtitle,0-mPaint.measureText(mtitle)/2,0,mPaint); } }
下部
从重写ViewGroup
链接: http://blog.****.net/silently_frog/article/details/79107827
这里要提下上面用到的关于自定义View与ViewGroup监听事件,自己去百度。这关于事务的分发机制。是Android的一个重点,肯定我要再下一页。
最后习惯性的提几个知识,便于自己知识的系统性:
ViewManager-----是一个接口类,功能为增加,删除,更新View.
ViewParent------也是一个接口类,功能自己去看源码,现在的我不怎么看的懂。需要说一下,它的实现类ViewGroup这个容器类,所以我猜测其里面应该定义的是ViewGroup容器操作子View特有的方法。
requestLayout()-----这个方法为请求重新布局。它调用自己父容器的requestLayout,其父容器又会调用它的父容器的requestLayout方法,即requestLayout事件层层向上传递,直到DecorView,即根View,而根View又会传递给ViewRootImpl,也即是说子View的requestLayout事件,最终会被ViewRootImpl接收并得到处理。纵观这个向上传递的流程,其实是采用了责任链模式,即不断向上传递该事件,直到找到能处理该事件的上级,在这里,只有ViewRootImpl能够处理requestLayout事件。从measure开始,对于每一个含有标记位的view及其子View都会进行测量、布局、绘制。
invalidate()------ 该方法的调用会引起View树的重绘,常用于内部调用(比如 setVisiblity())或者需要刷新界面的时候,需要在主线程(即UI线程)中调用该方法。
requestLayout()是测量、布局、绘制View的,而invalidate()是通知UI更新的。。