• Android自定义View初步


      经过上一篇的介绍,大家对于自定义View一定有了一定的认识,接下来我们就以实现一个图片下显示文字的自定义View来练习一下。废话不多说,下面进入我们的正题,首先看一下我们的思路,1、我们需要通过在values文件夹下添加一个attrs的文件,里面设置我们的自定义属性;2、通过重写View类,来获得我们设置的自定义属性的参数,并进行绘制;3、在我们的视图文件中进行引用。好了到这里我们的基本思路就已经形成,下面我们开始进行我们的实战编码操作。

      第一步:在res目录下,values文件夹下,新建一个attrs.xml文件:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        
        <attr name="TitleText" format="string" />
        <attr name="TitleColor" format="color" />
        <attr name="TitleSize" format="dimension" />
        
        <attr name="image" format="reference" />
        <attr name="imageScaleType">
            <enum name="fillXY" value="0" />
            <enum name="center" value="1" />
        </attr>
        
        <declare-styleable name="CustomImageView">
            <attr name="TitleText" />  
            <attr name="TitleColor" />  
            <attr name="TitleSize" />
            <attr name="image" />
            <attr name="imageScaleType" />
        </declare-styleable>
        
    </resources>

      提示一下:format对应的是该参数的值类型

      第二步:重写我们的View类:

    public class MySelfImageView extends View {
        
        /*
         * 图片区域
         */
        Rect imageRect;
        /*
         * 文字区域
         */
        Rect titleRect;
        /*
         * 画笔对象
         */
        Paint mPaint;
        /*
         * 图片标题文字
         */
        String titleText;
        /*
         * 图片标题文字颜色
         */
        int titleColor;
        /*
         * 图片标题文字大小
         */
        int titleSize;
        /*
         * 图片资源
         */
        Bitmap image;
        /*
         * 图片资源显示样式
         */
        int imageFillXY;
        
        int mWidth = 0;
        int mHeight = 0;
        
        public MySelfImageView(Context context) {
            this(context, null);
        }
    
        public MySelfImageView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public MySelfImageView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            //获取自定义设置的属性
            TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyleAttr, 0);
            int n = typedArray.getIndexCount();
            for(int i=0; i<n; i++){
                int att = typedArray.getIndex(i);
                //分别取出自定义属性设置的值
                switch (att) {
                    case R.styleable.CustomImageView_TitleText:
                        titleText = typedArray.getString(att);
                        break;
                    case R.styleable.CustomImageView_TitleColor:
                        titleColor = typedArray.getColor(att, Color.RED);        
                        break;
                    case R.styleable.CustomImageView_TitleSize:
                        titleSize = typedArray.getDimensionPixelSize(att, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,  
                                16, getResources().getDisplayMetrics())); 
                        break;
                    case R.styleable.CustomImageView_image:
                        image = BitmapFactory.decodeResource(getResources(), typedArray.getResourceId(att, 0));
                        break;
                    case R.styleable.CustomImageView_imageScaleType:
                        imageFillXY = typedArray.getInt(att, 0);
                        break;
                }
            }
            typedArray.recycle();
            
            imageRect = new Rect();
            mPaint = new Paint();
            titleRect = new Rect();
            mPaint.setTextSize(titleSize);
            // 计算描绘字体需要的范围
            mPaint.getTextBounds(titleText, 0, titleText.length(), titleRect);
        }
        
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            /** 
             * 设置宽度 
             */
            int specMode = MeasureSpec.getMode(widthMeasureSpec);
            int specSize = MeasureSpec.getSize(widthMeasureSpec);
            
            if(specMode == MeasureSpec.EXACTLY){
                mWidth = specSize;
            }else{
                // 由图片决定的宽  
                int desireByImg = getPaddingLeft() + getPaddingRight() + image.getWidth();  
                // 由字体决定的宽  
                int desireByTitle = getPaddingLeft() + getPaddingRight() + titleRect.width();  
          
                if (specMode == MeasureSpec.AT_MOST){// wrap_content  
                    int desire = Math.max(desireByImg, desireByTitle);
                    mWidth = Math.min(desire, specSize);
                }  
            }
            
            /** 
             * 设置高度 
             */
            specMode = MeasureSpec.getMode(heightMeasureSpec);
            specSize = MeasureSpec.getSize(heightMeasureSpec);
            
            if(specMode == MeasureSpec.EXACTLY){
                mHeight = specSize;
            }else{
                int desire = getPaddingTop() + getPaddingBottom() + image.getHeight() + titleRect.height();  
                if (specMode == MeasureSpec.AT_MOST){// wrap_content  
                    mHeight = Math.min(desire, specSize);
                }  
            }
            setMeasuredDimension(mWidth, mHeight);
        }
        
        @Override
        protected void onDraw(Canvas canvas) {
            /** 
             * 边框 
             */  
            mPaint.setStrokeWidth(4);//设置空心线宽  
            mPaint.setStyle(Paint.Style.STROKE);//设置画笔为空心 
            mPaint.setColor(Color.CYAN);//设置画笔颜色  
            canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);  
      
            imageRect.left = getPaddingLeft();  
            imageRect.right = mWidth - getPaddingRight();  
            imageRect.top = getPaddingTop();  
            imageRect.bottom = mHeight - getPaddingBottom();  
      
            mPaint.setColor(titleColor);  
            mPaint.setStyle(Style.FILL);  
            /** 
             * 当前设置的宽度小于字体需要的宽度,将字体改为xxx... 
             */  
            if (titleRect.width() > mWidth) {  
                TextPaint paint = new TextPaint(mPaint);  
                String msg = TextUtils.ellipsize(titleText, paint, (float) mWidth - getPaddingLeft() - getPaddingRight(),  
                        TextUtils.TruncateAt.END).toString();  
                canvas.drawText(msg, getPaddingLeft(), mHeight - getPaddingBottom(), mPaint);
            } else {  
                //正常情况,将字体居中  
                canvas.drawText(titleText, mWidth / 2 - titleRect.width() * 1.0f / 2, mHeight - getPaddingBottom(), mPaint);
            }  
      
            //取消使用掉的块 
            imageRect.bottom -= titleRect.height();  
      
            if (imageFillXY == 0) {
                canvas.drawBitmap(image, null, imageRect, mPaint);  
            } else {  
                //计算居中的矩形范围  
                imageRect.left = mWidth / 2 - image.getWidth() / 2;  
                imageRect.right = mWidth / 2 + image.getWidth() / 2;  
                imageRect.top = (mHeight - titleRect.height()) / 2 - image.getHeight() / 2;  
                imageRect.bottom = (mHeight - titleRect.height()) / 2 + image.getHeight() / 2;  
      
                canvas.drawBitmap(image, null, imageRect, mPaint);  
            } 
        }
    
    }

      第三步:布局文件

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:zhy="http://schemas.android.com/apk/res/com.example.myselfview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        
        <com.example.myselfview.view.MySelfImageView  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:layout_margin="10dp"  
            android:padding="10dp"  
            zhy:image="@drawable/ic_launcher"  
            zhy:imageScaleType="center"  
            zhy:TitleText="hello andorid ! "  
            zhy:TitleColor="#ff0000"  
            zhy:TitleSize="30sp" />  
      
        <com.example.myselfview.view.MySelfImageView 
            android:layout_width="100dp"  
            android:layout_height="wrap_content"  
            android:layout_margin="10dp"  
            android:padding="10dp"  
            zhy:image="@drawable/ic_launcher"  
            zhy:imageScaleType="center"  
            zhy:TitleText="helloworldwelcome"  
            zhy:TitleColor="#00ff00"  
            zhy:TitleSize="20sp" />  
      
        <com.example.myselfview.view.MySelfImageView  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:layout_margin="10dp"  
            android:padding="10dp"  
            zhy:image="@drawable/im"  
            zhy:imageScaleType="center"  
            zhy:TitleText="山水美景"  
            zhy:TitleColor="#ff0000"  
            zhy:TitleSize="12sp" />
    
    </LinearLayout>

      最后效果图:

      

      相对第一、三步,第二步相对更复杂一些,下面我就对第二步里面的具体内容进行一下解析:

    //获取自定义设置的属性
            TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyleAttr, 0);
            int n = typedArray.getIndexCount();
            for(int i=0; i<n; i++){
                int att = typedArray.getIndex(i);
                //分别取出自定义属性设置的值
                switch (att) {
                    case R.styleable.CustomImageView_TitleText:
                        titleText = typedArray.getString(att);
                        break;
                    case R.styleable.CustomImageView_TitleColor:
                        titleColor = typedArray.getColor(att, Color.RED);        
                        break;
                    case R.styleable.CustomImageView_TitleSize:
                        titleSize = typedArray.getDimensionPixelSize(att, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,  
                                16, getResources().getDisplayMetrics())); 
                        break;
                    case R.styleable.CustomImageView_image:
                        image = BitmapFactory.decodeResource(getResources(), typedArray.getResourceId(att, 0));
                        break;
                    case R.styleable.CustomImageView_imageScaleType:
                        imageFillXY = typedArray.getInt(att, 0);
                        break;
                }
            }
            typedArray.recycle();

      作用是获取我们在attrs中设置的自定义参数,在布局文件中进行的赋值。

      onMeasure()方法用于设置控件的宽度,控件的长宽值如何取得呢?下面我们就来进行一下解析:

      

      最后是我们绘图方法onDraw(Canvas canvas):

    @Override
        protected void onDraw(Canvas canvas) {
            /** 
             * 空心矩形绘制 
             */  
            mPaint.setStrokeWidth(4);//设置空心线宽  
            mPaint.setStyle(Paint.Style.STROKE);//设置画笔为空心 
            mPaint.setColor(Color.CYAN);//设置画笔颜色  
            canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);  
      
            imageRect.left = getPaddingLeft();//获取图片左上角坐标  
            imageRect.right = mWidth - getPaddingRight();//获取图片右上角坐标  
            imageRect.top = getPaddingTop();//获取图片距控件顶部距离  
            imageRect.bottom = mHeight - getPaddingBottom();//确定图片底部坐标  
      
            mPaint.setColor(titleColor);//设置文本的颜色  
            mPaint.setStyle(Style.FILL);//设置文本内容的填充方式  
            /** 
             * 当前设置的宽度小于字体需要的宽度,将字体改为xxx... 
             */  
            if (titleRect.width() > mWidth) {  
                TextPaint paint = new TextPaint(mPaint);  
                String msg = TextUtils.ellipsize(titleText, paint, (float) mWidth - getPaddingLeft() - getPaddingRight(),  
                        TextUtils.TruncateAt.END).toString();  
                canvas.drawText(msg, getPaddingLeft(), mHeight - getPaddingBottom(), mPaint);
            } else {  
                //正常情况,将字体居中  
                canvas.drawText(titleText, mWidth / 2 - titleRect.width() * 1.0f / 2, mHeight - getPaddingBottom(), mPaint);
            }  
      
            //取消使用掉的块 
            imageRect.bottom -= titleRect.height();//因为文字内容占用一定的高度,所以图片的底部坐标需要上移。  
      
            if (imageFillXY == 0) {
                canvas.drawBitmap(image, null, imageRect, mPaint);  
            } else {  
                //计算居中的矩形范围  
                imageRect.left = mWidth / 2 - image.getWidth() / 2;  
                imageRect.right = mWidth / 2 + image.getWidth() / 2;  
                imageRect.top = (mHeight - titleRect.height()) / 2 - image.getHeight() / 2;  
                imageRect.bottom = (mHeight - titleRect.height()) / 2 + image.getHeight() / 2;  
      
                canvas.drawBitmap(image, null, imageRect, mPaint);  
            } 
        }

      好了,到这里关于自定义View的初步学习就介绍完毕,如果你有更好的关于自定义View的文章,欢迎留言交流。

  • 相关阅读:
    20191208浙江自然博物馆寒武纪迸发专题展
    Spring Crest-英特尔出品的神经网络训练场景加速卡
    20191203动物园玉皇山凤凰山南宋皇城遗址凤凰山玉皇山动物园
    博观而约取-观展攻略
    20191130周六浙江美术馆纤维艺术特展
    git clone下载速度很慢的解决方法
    Jupyter notebook使用技巧积累
    (转)Python--matplotlib绘图可视化知识点整理
    Pygame一些不错教程平时收集....
    pygame.Surface.get_at
  • 原文地址:https://www.cnblogs.com/AndroidJotting/p/5460646.html
Copyright © 2020-2023  润新知