3、View中相比较关键的回调方法,那实在自定义view也分为好二种

前言

在念书的道路上,有一句跨领域的话正是“教永远是最佳的学”!那么自个儿梦想由此投机的分享能够更好的助手到有的必要的人!
笔者也能够对自个儿的供不应求实行回看!

自定义View在android开发中,可以说是一件感觉比较高档的事体了,那实在自定义view也分为好二种!平常来说大家也给她分为多个层次:

  1. 扩展已有控件
  • 创造复合控件
  • 贯彻全新的控件

注:以下笔记皆以由此《Android群英传》那本书整理而来。

正文

在此地自身也为我们准备了2个实例FlashTextView
先看一下功用图
那是不或者的,我们把奢侈留到最终!1上来就高潮,那是壹种病,得治!

本条意义实在正是通过对TextView举行二个简练的扩充就可知落实

1、大家不可能机械地记得全体绘图的API,而是要让那么些API为您所用,结合现实中的绘图方法,甚至是Photoshop的技术,才能设计出更好的自定义View。二、三个用户觉得熟悉的控件才是好的控件,切记勿追求华而不实。三、View中比较关键的回调方法:

1.实现

第叁大家先创立三个类让它集成TextView

public class FlashTextView extends TextView 

完结其构造方法,并在构造方法中开首化大家要用到的对象

public FlashTextView(Context context) {
    super(context);
    init();
}

public FlashTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public FlashTextView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
}

   private void init() {
    //初始化用来绘制背景边框的笔
    mPaint1=new Paint();
    mPaint2=new Paint();
    mPaint1.setColor(Color.RED);
    mPaint2.setColor(Color.GRAY);
    mPaint1.setStyle(Paint.Style.FILL);
    mPaint2.setStyle(Paint.Style.FILL);
}

上边是有关闪动作效果果落到实处,大家能够利用android中Paint对象的shader渲染器。通过设置1个持续变更的习性给LinearGradient,再用该Paint对象绘制要来得的文字!

先在onSizeChanged()方法中举行对象的伊始化学工业作

 @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    //闪动效果的对象初始化工作
    if(mViewWidth==0){
        mViewWidth=getMeasuredWidth();
        if(mViewWidth>0){
            //通过getPaint()方法获取绘制TextView的画笔
            mPaint=getPaint();
            mLinearGradient= new LinearGradient(0,0,mViewWidth,0,
                    new int[]{Color.BLACK,0xffffffff,Color.BLACK}, 
                    null,Shader.TileMode.CLAMP);
            //将该属性赋予给paint对象的shader渲染器
            mPaint.setShader(mLinearGradient);
            mGradientMatrix =new Matrix();
        }
    }
}

下一场大家再在onDraw方法中绘制出边框,背景;并由此矩阵的格局来不断移动渐变效果。最终达到大家想要的意义

 @Override
protected void onDraw(Canvas canvas) {
    //绘制字体之前
    //我们在这里绘制外矩形
    canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint1);
    //绘制内矩形
    canvas.drawRect(5,5,getMeasuredWidth()-5,getMeasuredHeight()-5,mPaint2);
    //绘制字体之前向右平移5像素
    canvas.translate(5,0);
    canvas.save();
    //开始绘制字体
    super.onDraw(canvas);
    //绘制字体之后
    canvas.restore();
    if (mGradientMatrix !=null){
        mTranslate += mViewWidth / 5;
        if(mTranslate>2*mViewWidth){
            mTranslate=-mViewWidth;
        }
        mGradientMatrix.setTranslate(mTranslate,0);
        mLinearGradient.setLocalMatrix(mGradientMatrix);
        postInvalidateDelayed(100);
    }
}
  • onFinishInflate():从XML加载组件后回调。

2.使用

以此就比较简单而来,就好像我们平日利用TextView壹样,只是供给专注的的是运用该类的全路径

 <com.timen.ronny.newtextview.view.FlashTextView
    android:layout_marginTop="30dp"
    android:textColor="@android:color/black"
    android:id="@+id/text2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Android程序员日记 "
    android:padding="5dp"
    android:textSize="30dp"
    android:layout_centerHorizontal="true" />
  • onSizeChanged():组件大小改变时。
  • onMeasure():回调该方法来开始展览衡量。
  • onLayout():回调该措施来规定彰显的任务。
  • onTouchEvent():监听到触摸事件时回调。

3.看效果

憋坏了啊!结果来看那般大学一年级个广告,别打作者,下次给你放美丽的女人图!

案例一:

4.扩展

自家想对于新手(也正是自小编本身,不指别人)来讲,诸如Matrix、LinearGradient大概未有接触过。关于那几个类和api,笔者提议大家能够协调去查一下,究竟自身出手弄驾驭的东西,印象会尤其的深入!所以在那里本身就不复制粘贴了!

那扩展扩的,跟没扩①样!话倒霉这么讲啊!毕竟:

授人以鱼,比不上授人以渔!

图片 11.pngpart壹:在结构中开创两支画笔,1支画背景1支画边框。

后记

小结一下对于自定义控件,用到比较多,也正如首要的回调方:

  • onFinishInflate():加载完XML组件后回调
  • onSizeChanged():组件大小改变时回调
  • onMeasure():回调该方法来开始展览度量
  • onLayout():回调该措施来呈现位置
  • onTouch伊芙nt():监听到触摸事件回调

那么扩充型自定义(其实应当称为半自定义)View的兑现,正是在原本控件的功底上通过地点的那壹部分回调方法来添加达成您想要的片段效应,比如上边13分带背景框和字体闪动作效果果TextView。

我的github源码:https://github.com/luorenyu/FlashTextView.git

最首要:喜欢就扫描下边包车型客车功用图关注我的众生号


mPaint1 = new Paint();mPaint1.setColor(getResources().getColor(android.R.color.holo_blue_light));mPaint1.setStyle(Paint.Style.FILL);// 设置风格为实心mPaint2 = new Paint();mPaint2.setColor(Color.YELLOW);mPaint2.setStyle(Paint.Style.FILL);

part贰:在onDraw方法中绘制。

@Overrideprotected void onDraw(Canvas canvas) { canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint1); //绘制内层矩形 canvas.drawRect(10,10,getMeasuredWidth()-10,getMeasuredHeight()-10,mPaint2); canvas.save(); //绘制文字前平移10像素 canvas.translate; //在回调父方法前,实现自己的逻辑,对TextView来说就是在绘制文本内容前 super.onDraw; canvas.restore();}

案例二:

图片 2闪动的文字效果.pngpart1:一、在onSizeChanged中开端化壹些对象,是因为在该措施中组件的轻重才真的改变,才能得到零部件的长度宽度被这一个指标所用。二、利用Paint对象的Shader渲染器,通过设置3个持续转变的LinearGradient,并行使带该属性的Paint来绘制要来得的文字。三、最注重的正是选取getPaint()方法赢伏贴前绘制TextView的Paint对象,并给Paint设置原生TextView未有的LinearGradient属性。

@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if(mViewWidth == 0){ mViewWidth = getMeasuredWidth(); if(mViewWidth>0){ mPaint = getPaint(); // 注意这个地方不要写成new Paint() //参数一为渐变起初点坐标x位置,参数二为y轴位置,参数三和四分辨对应渐变终点, //参数五是参与渐变效果的颜色集合 //参数六是定义每个颜色处于的渐变相对位置,这个参数可以为null,如果为null表示所有的颜色按顺序均匀的分布 //最后参数为平铺方式 mLinearGradient = new LinearGradient( 0,0,mViewWidth,0,new int[]{ Color.BLUE,0xffffffff,Color.BLUE },null, Shader.TileMode.CLAMP); mPaint.setShader(mLinearGradient); mGradientMatrix = new Matrix(); } }}

part二:通过矩阵的方法来持续运动渐变效果,在绘制文字时,发生动态的闪动作效果果。

@Overrideprotected void onDraw(Canvas canvas) { super.onDraw; if(mGradientMatrix!=null){ mTranslate += mViewWidth/10; if(mTranslate > 2 * mViewWidth){ mTranslate = -mViewWidth; } mGradientMatrix.setTranslate(mTranslate,0); mLinearGradient.setLocalMatrix(mGradientMatrix); postInvalidateDelayed; }}

书上的案例太不难,代码有点多那里就不贴了。不难计算一下正是分为多个步骤:一、自定义属性

壹、在res能源目录下values目录下开创attrs.xml属性定义文件。

<resource> <declare-styleable name="一般这里写控件的名字"> <attr name="属性名" format="属性类型,可以用"|"分隔不同的属性"/> </declare-styleable></resouce>

二、在组织中用代码获取xml布局中自定义的那二个属性。

TypeArray ta = context.obtainStyledAttributes(attr,R.styleable.控件名);属性类型 属性值 = ta.get属性类型(R.styleable.属性名);ta.recycler();//调用recycler完成资源回收

2、组合控件

一、为创立的机件元素赋值,值就来源于大家在引用的xml文件中给对应属性的赋值。

Button btn1 = new Button;btn1.setTextColor;

贰、为组件成分设置响应的布局成分。

LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);params .addRule(ALIGN_PARENT_RIGHT,TRUE);

3、添加到ViewGroup。

addView(btn1,params);

3、定义接口。4、揭发接口给调用者。

案例三:

图片 3案例叁.pngpart1:在构造方法中伊始化对象。

WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);int screenWidth = wm.getDefaultDisplay().getWidth();//圆心mCircleXY = screenWidth/2;//圆的半径mRadius =  (screenWidth*0.5/2);//指定圆弧的外轮廓矩形区域mArcRectF = new RectF(screenWidth*0.1),(screenWidth*0.1),(screenWidth*0.9),(screenWidth*0.9));mCirclePaint = new Paint();mCirclePaint.setColor(Color.BLUE);mArcPaint = new Paint();mArcPaint.setStyle(Paint.Style.STROKE);mArcPaint.setStrokeWidth;mArcPaint.setColor(Color.GREEN);mTextPaint = new Paint();mTextPaint.setColor(Color.BLACK);mShowText = "哈哈哈哈";mShowTextSize = 40;

part二:分别绘制圆、圆弧、文字。

@Overrideprotected void onDraw(Canvas canvas) { //绘制圆 canvas.drawCircle(mCircleXY,mCircleXY,mRadius,mCirclePaint); //绘制弧线( // 参数1:指定圆弧的外轮廓矩形区域, // 参数2:圆弧起始角度,单位为度 // 参数3:圆弧扫过的角度,顺时针方向,单位为度,从右中间开始为零度 // 参数4:如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形 // 参数5:绘制圆弧的画板属性,如颜色,是否填充等。) canvas.drawArc(mArcRectF,270,270,false,mArcPaint); //绘制文字 canvas.drawText(mShowText,0,mShowText.length(),mCircleXY,mCircleXY+(mShowTextSize/4),mTextPaint);}

连带资料:android中canvas.drawText参数的牵线以及绘制1个文本居中的案例Android的DrawText详解怎么着“任性”使用Android的drawText()drawArc方法介绍案例四:

图片 4案例4.pngpart一:先在结构中开始化一些对象

WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);mWidth = wm.getDefaultDisplay().getWidth();mPaint = new Paint();mPaint.setColor(Color.BLUE);

part2:在组件改变地方的时候给Paint扩展三个LinearGradient渐变效果。

@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = getWidth(); mRectHeight= getHeight(); mRectWidth = (mWidth*0.6/mRectCount); LinearGradient mLinearGradient = new LinearGradient(0,0,mRectWidth,mRectHeight, Color.YELLOW,Color.BLUE, Shader.TileMode.CLAMP); mPaint.setShader(mLinearGradient);}

part三:在onDraw中循环绘制。

@Overrideprotected void onDraw(Canvas canvas) { super.onDraw; for (int i = 0;i<mRectCount;i++){ double random = Math.random(); //每个矩形的高 float currentHeight =  (mRectHeight*random); canvas.drawRect(mWidth*0.4/2+mRectWidth*i+offset), currentHeight,(mWidth*0.4/2+mRectWidth*, mRectHeight,mPaint); }}

明日敲了2遍书上的案例,有个别地方还不是很消化,例如绘制文字这块依旧略模糊,明天持续更自定义ViewGroup。

壹、ViewGroup的目标就是为了对其子View实行保管。二、ViewGroup常常要重写onMeasure()方法对子View实行衡量,重写onLayout()鲜明子View的地点,重写onTouch伊芙nt()扩充响应事件。

案例5://TODO:待插入gif图part一:在构造函数中早先化一些指标:

mScroller = new Scroller;WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);mScreenHeight = wm.getDefaultDisplay().getHeight();

part二:在onMeasure中给子View进行度量。

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int count = getChildCount(); for (int i=0;i<count;i++){ View childView = getChildAt; //用遍历的方式给子View测量 measureChild(childView,widthMeasureSpec,heightMeasureSpec); }}

part三:遍历设定各种子View供给摆放的任务,直接通过调用子View的layout方法,将具体的参数字传送入即可。

@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) { int childCount = getChildCount(); //设置ViewGroup的高度 MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams(); //这里让每个子View都显示完整的一屏 mlp.height = mScreenHeight*childCount; setLayoutParams; for (int i = 0;i<childCount;i++){ View child = getChildAt; if(child.getVisibility{ //修改每个子View的top和bottom两个属性,让他们可以依次排列下来 child.layout(l,i*mScreenHeight,r,*mScreenHeight); } }}

part四:在onTouch伊夫nt中落到实处滚动的逻辑和”粘性”的逻辑。

 @Overridepublic boolean onTouchEvent(MotionEvent event) { int y = event.getY(); switch(event.getAction{ case MotionEvent.ACTION_DOWN: mLastY = y; //记录触摸起点 mStart = getScrollY(); break; case MotionEvent.ACTION_MOVE: if(!mScroller.isFinished{ mScroller.abortAnimation(); } int dy = mLastY - y; if(getScrollY{ dy = 0; } if(getScrollY()>getHeight()-mScreenHeight){ dy = 0; } scrollBy; mLastY = y; break; case MotionEvent.ACTION_UP: //记录触摸终点 mEnd = getScrollY(); int dScrollY = mEnd - mStart; if(dScrollY>0){ if(dScrollY<mScreenHeight/3){ mScroller.startScroll(0,getScrollY(),0,-dScrollY); }else{ mScroller.startScroll(0,getScrollY(),0,mScreenHeight-dScrollY); } }else{ if(-dScrollY<mScreenHeight/3){ mScroller.startScroll(0,getScrollY(),0,-dScrollY); }else{ mScroller.startScroll(0,getScrollY(),0,-mScreenHeight-dScrollY); } } break; } postInvalidate(); return true;}@Overridepublic void computeScroll() { super.computeScroll(); if(mScroller.computeScrollOffset{ scrollTo(0,mScroller.getCurrY; postInvalidate(); }}

相关文章

网站地图xml地图