Android菜鸡的提升之路---自定义View简单的实现

本文介绍如何在Android中创建自定义View,并实现简单的文本视图组件。通过实例演示如何使用AttributeSet和TypedArray来获取XML中定义的属性。

首先,先实行一个最简单的自定义View来学习一下有关的属性:

1.在res/values下新建一个xml文件,这里取名hl_attr.xml

在里面定义一些属性:


在写View的时候可以获取属性:

package com.example.admin.my_view.my_view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.support.v7.widget.AppCompatTextView;
import android.widget.TextView;

import com.example.admin.my_view.R;

/**
 * Created by admin on 2018/4/26.
 */

public class my_text_view extends AppCompatTextView{
    private TypedArray mTypedArray;
    //TypedArray:TypedArray是存储资源数组的容器,
    // 他可以通过obtaiStyledAttributes()方法创建出来。
    // 不过创建完后,如果不在使用了,请注意调用recycle()方法把它释放。
    //通过TypedArray来获取xml里面的资源文件
    private Paint mPaint;

    public my_text_view(Context context){
        super(context);//调用父类的构造函数
    }

    public my_text_view(Context context, AttributeSet attributeSet){
        //ArrtibuteSet 获取xml文件的属性的特征,说明,一般用来传递资源,比如传递给TypedArray.
        super(context,attributeSet);//继续调用父类构造函数
        init(context,attributeSet);//绑定对应的资源文件
    }

    public my_text_view(Context context,AttributeSet attributeSet,int defStyle){
        super(context,attributeSet,defStyle);
        init(context,attributeSet);
    }

    private void init(Context context,AttributeSet attributeSet){
        TypedArray typedArray = context.obtainStyledAttributes(attributeSet,
                R.styleable.my_view);//可以利用typedArray来获取定义过的属性
        float textsize = typedArray.getFloat(R.styleable.my_view_my_text_size,30);

        int textcolor = typedArray.getColor(R.styleable.my_view_my_text_color,0x000000);

       int bgcolor = typedArray.getColor(R.styleable.my_view_my_text_background,0xffffff);
        String text = typedArray.getString(R.styleable.my_view_my_text);

        super.setTextSize(textsize);
        super.setTextColor(textcolor);
        super.setBackgroundColor(bgcolor);
        //super.setText(text);
        super.setText(text);


        typedArray.recycle();//释放

    }




}
这里是全部的代码。(真的很少)

最后调用:

<com.example.admin.my_view.my_view.my_text_view
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:my_text_size="30"
    app:my_text_color="#48ed44"
    app:my_text="Hdssasdad"
    android:layout_marginLeft="150dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:layout_marginTop="163dp" />

很简单,因为是继承TextView,上面每一个参数我几乎都有注释,新手应该比较幸福,因为我当时查的比较累(hhh),那么在上面我们学到了如何设置属性,和利用AttributeSet去得到资源的信息,如何传递给TypedArray,让它去解析获取调出我们之前定义的属性。下面我们要难一点点,就是继承于View去实现一个TextView:

package com.example.admin.my_view.my_view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;

import com.example.admin.my_view.R;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by admin on 2018/4/26.
 */

public class my_view_text extends View {

    private String mtext; //文字
    private List<String> mtextlist;//文本列表
    private int mcolor;//yanse
    private float mtextsize;//大小
    private Rect mbound;//绘制的范围
    private Paint mpaint;//画笔

    boolean isoneLine = true;//文本只有一行?
    float lineNum;//文本的行数(只能整数)
    float splineNum;//文本的行数(计算需要,存在小数)
    public my_view_text(Context context){
        this(context,null);//调用第二种构造函数
    }
    public my_view_text(Context context , AttributeSet attributeSet){
        this(context,attributeSet,0);//调用第三种构造函数
    }
    public my_view_text(Context context,AttributeSet attributeSet,int defstyleattr ) {
        super(context, attributeSet, defstyleattr);//调用父类的构造函数


        TypedArray typedArray =context.obtainStyledAttributes(attributeSet, R.styleable.my_view);
        mtextlist = new ArrayList<String>();
        mtext = typedArray.getString(R.styleable.my_view_my_text);
        mcolor = typedArray.getColor(R.styleable.my_view_my_text_color,0xff0000);
        mtextsize = typedArray.getFloat(R.styleable.my_view_my_text_size,100);

        typedArray.recycle();//释放TypedArray

        mpaint = new Paint();//画笔对象
        mpaint.setColor(mcolor);
        mpaint.setTextSize(mtextsize);//设置画笔的属性

        mbound = new Rect();
        //getTextBounds参数:(文本,第一个字符,最后一个字符的后一个,RECT对象  用于存储测出的widthheight        mpaint.getTextBounds(mtext, 0, mtext.length(), mbound);

    }




//设置
    @Override
    protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
        super.onMeasure(widthMeasureSpec,heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);//获取宽的模式
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);//获取高的模式
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);//获取宽的尺寸
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);//获取高的尺寸

        //自动换行
        float textwidth = mbound.width();//文本的宽度
        if(mtextlist.size() == 0){
            int padding = getPaddingLeft() + getPaddingRight();//边距
            int xian_shi_width = widthSize - padding;//可显示文本的宽度
            //只有一行
            if(textwidth<xian_shi_width){
                lineNum = 1;
                isoneLine = true;
                mtextlist.add(mtext);
            }else{
                isoneLine=false;
                splineNum = textwidth/xian_shi_width; //需要显示行数
                if((splineNum+"").contains(".")){//先转化为字符串,然后判断是否存在“.”
                    lineNum = Integer.parseInt((splineNum+"").substring(0,(splineNum+"").indexOf(".")))+1;
                    //转化为字符串截取到点之前的字符 转化为int类型再加1                    //lineNum = (int)splineNum + 1;
                }else
                {
                    lineNum = splineNum;//整数型需要显示的行数
                }
                int lengthline = (int) (mtext.length() / splineNum);//每一行显示的字符的长度用于截取字符
                //把输入的一串字符串截取出一段段放入list                for(int i = 0; i<lineNum; i++){
                    String str;
                    if(mtext.length() < lengthline){
                        str = mtext.substring(0,mtext.length());//当前行显示的内容
                    //    mtext ="";//清空输入的长字符串

                    }else
                    {
                        str = mtext.substring(0,lengthline);//截取可以显示的当前行的内容
                      //  mtext = mtext.substring(lengthline,mtext.length());//切掉之前已经显示过的内容
                    }
                    mtextlist.add(str);
                    if(!TextUtils.isEmpty(mtext)) {
                        if(mtext.length()<lengthline){
                            mtext = mtext.substring(0, mtext.length());
                        }else{
                            mtext = mtext.substring(lengthline, mtext.length());
                        }
                    }else{
                        break;
                    }

                }
            }

        }



        int width;
        int height;
//设置宽度
        if(widthMode == MeasureSpec.EXACTLY){
            //match_parent或者其它具体的值
            width = widthSize;
        }
        else{
           //float textwidth = mbound.width();//文本的宽度
            //wrap_parent
            //getPaddingLeft内边距(距离左边) getPaddingRight(距离右边)
            //width = ( int )(getPaddingLeft() + textwidth + getPaddingRight());
            if(isoneLine)//单行
            width = ( int )(getPaddingLeft() + textwidth +getPaddingRight());
            else//多行直接给全部尺寸
            width = widthSize;


        }
//设置高度
        if(heightMode == MeasureSpec.EXACTLY){
            height = heightSize;
        }
        else
        {
            float textheight = mbound.height();
            //getPaddingLeft内边距(距离顶边) getPaddingRight(距离底边)
            if(isoneLine)
            height = ( int )(getPaddingTop() + textheight + getPaddingBottom());
            else
                height = ( int )(getPaddingTop() + textheight * lineNum + getPaddingBottom());



        }

        setMeasuredDimension(width,height);//保存宽度和高度


    }


    @Override
    protected void onDraw(Canvas canvas){
        //分行绘出文字

        for(int i = 0 ; i < mtextlist.size() ; i++) {
            mpaint.getTextBounds(mtextlist.get(i),0,mtextlist.get(i).length(),mbound);
            canvas.drawText(mtextlist.get(i),getWidth()/2 - mbound.width()/2,getPaddingTop()+(mbound.height()*i),mpaint);
        }

        //   canvas.drawText(mtext,getWidth()/2-mbound.width()/2,getHeight()/2+mbound.height()/2,mpaint);
    }



}


这里注释给的很全了,但是在显示的时候高度好像还是有点问题,没有做到和textview那么强大的自动换行对齐,但是我们还是先学下去。


### 使用 a-upload 组件实现自定义和批量文件上传 #### 1. 安装依赖项 为了使用 `a-upload` 组件,首先需要安装 Ant Design Vue 库。可以通过 npm 或 yarn 来完成这一操作。 ```bash npm install ant-design-vue --save ``` 或者 ```bash yarn add ant-design-vue ``` #### 2. 引入 a-upload 组件 在项目的入口文件或相应页面中引入 `a-upload` 组件: ```javascript import { Upload } from 'ant-design-vue'; app.use(Upload); ``` #### 3. 创建自定义批量文件上传功能 下面是一个完整的示例代码片段,展示了如何利用 `a-upload` 实现自定义的批量文件上传功能[^1]。 ```vue <template> <div id="upload-demo"> <!-- 多选文件 --> <a-upload :multiple="true" name="file" action="/your-server-endpoint" @change="handleChange" :beforeUpload="handleBeforeUpload" accept=".jpg,.png,.gif" > <button>点击选择文件</button> </a-upload> <!-- 展示已上传文件列表 --> <ul v-if="uploadedFiles.length > 0"> <li v-for="(file, index) in uploadedFiles" :key="index">{{ file.name }}</li> </ul> </div> </template> <script> export default { data() { return { uploadedFiles: [], // 存储成功上传后的文件信息 whiteList: ['jpg', 'png', 'gif'], // 允许上传的文件类型白名单 }; }, methods: { handleChange(info) { if (info.file.status === 'done') { this.uploadedFiles.push(info.file); // 将成功上传的文件加入数组 } }, handleBeforeUpload(file) { const fileType = file.type.split('/').pop().toLowerCase(); if (!this.whiteList.includes(fileType)) { alert(`仅支持 ${this.whiteList.join(',')} 类型`); return false; } return true; }, }, }; </script> ``` 此代码实现了如下特性: - 支持多文件选择 (`multiple=true`) - 设置了可接受的 MIME 类型 (`accept`) 及对应的文件扩展名过滤 - 提供了一个简单的回调函数来处理文件状态变化事件 (`@change=handleChange`) - 在上传前验证文件类型 (`:beforeUpload=handleBeforeUpload`) - 显示已经成功上传的文件名称列表 上述方法能够满足大多数场景下的基本需求,对于更复杂的需求,则可以根据实际情况调整配置选项或进一步定制化开发[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值