zoukankan      html  css  js  c++  java
  • 自定义控件,1,自定义属性;2,创建复合控件

    整理昨日在群英传上深入学习到的自定义view的知识

    一,对现有控件进行扩展:

    在原生控件的基础上进行拓展,增加新的功能、修改显示的UI等,一般来说,我们可以在onDraw()方法上对原生控件行为进行拓展

    以TextView的背景更加丰富,让Textview的背景更加丰富,给其多绘制几层背景。

    1.1

    原生的TextView使用onDraw()方法绘制要显示的文字。当继承了TextView之后如果不重写该方法,则不会修改Textview的任何效果

    @Override
        protected void onDraw(Canvas canvas) {
    
            //在回调父类方法前,实现自己的逻辑,对TextView来说即是在绘制文本前
            super.onDraw(canvas);
            //在回调父类方法后,实现自己的逻辑,对TextView来说即是在绘制文本后
        
    
        }    

    通过以上思路,就可以实现自定义TextView了。我们在构造方法中完成必要对象的初始化的工作。

    例如:初始化两个画笔paint;

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

    然后在绘制文字前,我们可以绘制两个不同大小的矩形,形成一个重叠效果,再让系统调用 super.onDraw(canvas)方法,执行绘制文字的工作。

    //绘制外层矩形
     canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint1);
    //绘制内层矩形
    canvas.drawRect(10,10,getMeasuredWidth()-10,getMeasuredHeight()-10,mPaint1);
    canvas.save();
    //绘制文字前平移10像素
    canvas.translate(10,0);
    super.onDraw(canvas);
    canvas.restore();

    1.2实现稍微复杂的TextView,实现动态文字的闪动效果。

    实现这个效果可以使用Paint对象的Shader渲染器。通过设置一个不断变化的LinearGradient,并使用带有该属性的Paint对象来绘制要显示的文字。首先要在onSizeChanged()方法中进行一些对象的初始化工作,并根据view的宽度设置一个LinearGradient

    渐变渲染器,代码如下:

    mViewWidth为view的宽度,通过getMeasure方法可以获取

    mPaint,这里最关键的一个地方,通过getPaint()方法获取当前绘制TextView的Paint对象

    mLinearGradient线性渐变属性,LinearGradient是基于Shader渲染器的

    @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){
                    //获取当前绘制TextView的Paint对象
                    mPaint=getPaint();
                    //LinearGradient是基于Shader渲染器的
                    mLinearGradient= new LinearGradient(
                            0,
                            0,
                            mViewWidth,
                            0,
                            new int[]{
                                    Color.BLUE,0xffffffff,
                                    Color.BLUE
                            },
                            null,
                            Shader.TileMode.CLAMP);
            //给paint设置原生TextView没有的LinearGradient的属性 mPaint.setShader(mLinearGradient);          //在这里初始化好Matrix的对象,用于接下来实现平移效果,当然设置matrix还可以实现其他效果,例如旋转,缩放等
    mGradientMatrix
    = new Matrix(); } } }

    最后,在onDraw()方法中,通过矩阵的方式来不断的平移效果,从而绘制文字时,产生动态的闪动效果。

    @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (mGradientMatrix != null) {
                mTranslate+=mViewWidth/5;
                if (mTranslate>2*mViewWidth){
                    mTranslate=-mViewWidth;
                }
                mGradientMatrix.setTranslate(mTranslate,0);//设置平移效果
                mLinearGradient.setLocalMatrix(mGradientMatrix);
                postInvalidateDelayed(100);
    
            }
    
        }

    最后效果是这样的:

    二、创建复合控件

    创建复合控件可以很好的创建出具有重用功能的控件集合,这种方式通常需要继承一个合适的ViewGroup,再给它添加指定的功能的控件,从而组合成新的符合控件

    我们一般会给它指定一些可配置的属性,让它具有更强的拓展性。

    定义一个topBar为例

    2.1定义属性:

    为一个View提供可定义的属性非常简单,只需要在res资源目录的values目录下创建一个attrs.xml的文件。

    name为属性的名称,format属性来指定属性的类型

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="TopBar">
            <attr name="title" format="string"/>
            <attr name="titleTextSize" format="dimension"/>
            <attr name="titleTextColor" format="color"/>
            <attr name="leftTextColor" format="color"/>
            <attr name="leftBackGround" format="reference|color"/>
            <attr name="leftText" format="string"/>
            <attr name="rightTextColor" format="color"/>
            <attr name="rightBackGround" format="reference|color"/>
            <attr name="rightText" format="string"/>
        </declare-styleable>
    </resources>
    系统提供了TypedArray这样的数据结构来获取自定义属性集,后面引用的styleable的TopBar,就是在xml中通过<delcare-styleable name="TopBar">所指定的name名。通过TypedArray的getString(),getColor()等方法,就可以获取这些定义的属性值。
    当获取完属性后,需要调用TypedArray的recyle方法来完成资源的回收
    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);
            mLeftTextColor=ta.getColor(R.styleable.TopBar_leftTextColor,0);
            mLeftBackGround=ta.getDrawable(R.styleable.TopBar_leftBackGround);
            mLeftText=ta.getString(R.styleable.TopBar_leftText);
    
            mRightTextColor=ta.getColor(R.styleable.TopBar_rightTextColor,0);
            mRightBackGround=ta.getDrawable(R.styleable.TopBar_rightBackGround);
            mRightText=ta.getString(R.styleable.TopBar_rightText);
    
            mTitleTextSize= ta.getDimension(R.styleable.TopBar_titleTextSize,10);
            mTitleTextColor=ta.getColor(R.styleable.TopBar_titleTextColor,0);
            mTitle=ta.getString(R.styleable.TopBar_title);
            //获取完TypedArray的值后,一般要调用recyle方法来回收资源避免重新创建的时候造成的错误
    
            ta.recycle();

    2.2组合控件

    //创建组件
            mLeftButton= new Button(context);
            mRightButton= new Button(context);
            mTitleView = new TextView(context);
            //为创建的组件元素赋值,值就来源于我们在引用的xml文件中给对应属性的属性值
            mLeftButton.setText(mLeftText);
            mLeftButton.setTextColor(mLeftTextColor);
            mLeftButton.setBackground(mLeftBackGround);
    
            mRightButton.setText(mRightText);
            mRightButton.setTextColor(mRightTextColor);
            mRightButton.setBackground(mRightBackGround);
    
            mTitleView.setText(mTitle);
            mTitleView.setTextColor(mTitleTextColor);
            mTitleView.setTextSize(mTitleTextSize);
            mTitleView.setGravity(Gravity.CENTER);
    
            //为组件元素设置相对应的布局元素
            mLeftParams= new LayoutParams(LayoutParams.WRAP_CONTENT,
                    LayoutParams.MATCH_PARENT);
            mLeftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE);
            addView(mLeftButton,mLeftParams);
    
            mRightParams= new LayoutParams(LayoutParams.WRAP_CONTENT,
                    LayoutParams.MATCH_PARENT);
            mRightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE);
            addView(mRightButton,mRightParams);
    
            mTitleParams= new LayoutParams(LayoutParams.WRAP_CONTENT,
                    LayoutParams.MATCH_PARENT);
            mTitleParams.addRule(RelativeLayout.CENTER_IN_PARENT,TRUE);
            addView(mTitleView,mTitleParams);

    要给左右按钮设计点击事件。每个调用者所需要这些按钮能够实现的功能都是不一样的,因此不能直接在UI模板中添加具体的实现逻辑

    定义接口

    public interface topbarClickListener{
            //左边按钮点击事件
            void leftClick();
            //右边按钮点击事件
            void rightClick();
        }

    对两个按钮设置监听事件

    mRightButton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mListener!=null)    //此处要判监听是否为空,否则在没有调用接口的情况下会报空指针异常
                    mListener.rightClick();
                }
            });
    mLeftButton.setOnClickListener(
    new OnClickListener() { @Override public void onClick(View v) { if (mListener!=null) //此处要判监听是否为空,否则在没有调用接口的情况下会报空指针异常
    mListener.leftClick(); } });

    暴露接口给调用者

    //暴露一个方法给调用者来注册接口调用,通过接口获得回调者对接口方法的实现
        public void setOnTopbarClickListener(topbarClickListener  listener){
            this.mListener=listener;
    
        }

    这样TopBar的基本功能就实现了,

    当然还可以提供其他的接口方法来设置TopBar的属性

    例如:提供setButtonVisiable方法来设置button是否显示

    public void setButtonVisable(int id,boolean flag){
            if (flag){
                if (id==0){
                    mLeftButton.setVisibility(VISIBLE);
                }else{
                    mRightButton.setVisibility(VISIBLE);
                }
            }else{
                if (id==0){
                    mLeftButton.setVisibility(GONE);
                }else{
                    mRightButton.setVisibility(GONE);
                }
            }
        }

    2.3如何引用自定义的UI模板

    第三方控件使用如下代码来引入名字空间。

    xmlns:custom="http://schemas.android.com/apk/res-auto"

    然后在xml文件中就可以使用自定义的属性了,使用custom来引用。我们进一步将这个UI模板写到一个布局文件中。

    <com.example.TopBar
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:custom="http://schemas.android.com/apk/res-auto"
    custom:leftBackGround="@color/blue"
        custom:leftText="Back"
        custom:leftTextColor="@color/yellow"
        custom:rightBackGround="@color/yellow"
        custom:rightText="More"
        custom:rightTextColor="@color/blue"
        custom:title="自定义标题"
        custom:titleTextColor="@color/black"
        custom:titleTextSize="10sp"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        >
    
    </com.example.TopBar>

    那么在其他布局文件中就可以通过<include>标签进行引用了

    如下所示

    <include layout="@layout/layout"/>
  • 相关阅读:
    spark机器学习从0到1特征抽取–Word2Vec(十四)
    spark机器学习从0到1特征抽取–CountVectorizer(十三)
    spark机器学习从0到1特征提取 TF-IDF(十二)
    spark机器学习从0到1机器学习工作流 (十一)
    vant ui中area组件踩坑记录
    免费CDN:jsDelivr+Github 使用方法
    使用vue-quill-editor实现富文本编辑器
    数组添加元素到特定位置
    scoop——强大的Windows命令行包管理工具
    radio单选框样式
  • 原文地址:https://www.cnblogs.com/fajieyefu/p/5995717.html
Copyright © 2011-2022 走看看