三 、View中比较根本的回调方法,那是一种病

前言

在攻读的道路上,有一句跨领域的话便是“教永远是最好的学”!那么本人期望由此投机的享受能够更好的增派到部分亟待的人!
小编也能够对协调的供不应求进行回看!

自定义View在android开发中,能够说是一件感觉相比较高档的事务了,那实在自定义view也分为好两种!平常来说大家也给他分为多少个层次:

  1. 壮大已有控件
  • 创立复合控件
  • 落到实处全新的控件

注:以下笔记都以经过《Android群英传》这本书整理而来。

正文

在此间本身也为我们准备了2个实例FlashTextView
先看一下功效图
这是不容许的,大家把豪华留到最终!一上来就高潮,那是一种病,得治!

以此效应其实正是由此对TextView实行一个不难易行的恢宏就可见实现

① 、我们无法机械地记得全部绘图的API,而是要让那些API为你所用,结合实际中的绘图方法,甚至是Photoshop的技艺,才能设计出更好的自定义View。二 、叁个用户认为熟识的控件才是好的控件,切记勿追求华而不实。三 、View中相比主要的回调方法:

1.实现

率先大家先创设3个类让它集成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渲染器。通过设置一个频频变动的个性给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.pngpart1:在布局中成立两支画笔,一支画背景一支画边框。

后记

总计一下对此自定义控件,用到比较多,也正如主要的回调方:

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

那便是说扩张型自定义(其实应该叫做半自定义)View的完成,正是在原有控件的根底上经过地点的那有的回调方法来添加完结您想要的一些功能,比如上边11分带背景框和字体闪动作效果果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);

part2:在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渲染器,通过安装贰个频频变化的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(); } }}

part2:通过矩阵的主意来不断运动渐变效果,在绘制文字时,发生动态的闪动作效果果。

@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完成资源回收

二 、组合控件

一 、为创制的零部件成分赋值,值就来源于大家在引用的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案例三.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;

part2:分别绘制圆、圆弧、文字。

@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参数的介绍以及绘制3个文本居中的案例Android的DrawText详解怎么着“任性”使用Android的drawText()drawArc方法介绍案例四:

图片 4案例四.pngpart1:先在布局中开始化一些目的

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);}

part3:在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); }}

后天敲了3遍书上的案例,有个别地点还不是很消化,例如绘制文字这块如故略模糊,今天延续更自定义ViewGroup。

壹 、ViewGroup的指标正是为着对其子View举办田管。贰 、ViewGroup常常要重写onMeasure()方法对子View进行度量,重写onLayout()分明子View的地方,重写onTouch伊芙nt()增加响应事件。

案例5://TODO:待插入gif图part1:在构造函数中开首化一些指标:

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

part2:在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); }}

part3:遍历设定各类子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); } }}

part4:在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(); }}