Android Custom View (2) Advancement

Keywords: Android xml encoding less

For reprinting, please indicate the source: http://blog.csdn .NET/lmj623565791/article/details/24300125

Continue with the customized View tour. An example of the basis of a customized View has been described earlier. Android Custom View (1) If you still don't know about custom View, you can go and see it. Today I'm going to give you a slightly more complicated example.

Custom View displays a picture. The text description of the picture is included below. It's similar to what the photo describes. But it's not important. It's mainly about learning the usage of Custom View.

Do you remember the four steps in the last article?

1. Properties of custom View
2. Obtain our custom attributes in View's construction method
[3. Rewrite onMesure]
4. Rewrite onDraw

Directly cut into the main topic:

1. At res/values/attr.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.   
  4.     <attr name="titleText" format="string" />  
  5.     <attr name="titleTextSize" format="dimension" />  
  6.     <attr name="titleTextColor" format="color" />  
  7.     <attr name="image" format="reference" />  
  8.     <attr name="imageScaleType">  
  9.         <enum name="fillXY" value="0" />  
  10.         <enum name="center" value="1" />  
  11.     </attr>  
  12.   
  13.     <declare-styleable name="CustomImageView">  
  14.         <attr name="titleText" />  
  15.         <attr name="titleTextSize" />  
  16.         <attr name="titleTextColor" />  
  17.         <attr name="image" />  
  18.         <attr name="imageScaleType" />  
  19.     </declare-styleable>  
  20.   
  21. </resources>  
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <attr name="titleText" format="string" />
    <attr name="titleTextSize" format="dimension" />
    <attr name="titleTextColor" format="color" />
    <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="titleTextSize" />
        <attr name="titleTextColor" />
        <attr name="image" />
        <attr name="imageScaleType" />
    </declare-styleable>

</resources>

2. Get our custom attributes in the construction:

  1. /** 
  2.      * Initialize custom types that are specific to 
  3.      *  
  4.      * @param context 
  5.      * @param attrs 
  6.      * @param defStyle 
  7.      */  
  8.     public CustomImageView(Context context, AttributeSet attrs, int defStyle)  
  9.     {  
  10.         super(context, attrs, defStyle);  
  11.   
  12.         TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyle, 0);  
  13.   
  14.         int n = a.getIndexCount();  
  15.   
  16.         for (int i = 0; i < n; i++)  
  17.         {  
  18.             int attr = a.getIndex(i);  
  19.   
  20.             switch (attr)  
  21.             {  
  22.             case R.styleable.CustomImageView_image:  
  23.                 mImage = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0));  
  24.                 break;  
  25.             case R.styleable.CustomImageView_imageScaleType:  
  26.                 mImageScale = a.getInt(attr, 0);  
  27.                 break;  
  28.             case R.styleable.CustomImageView_titleText:  
  29.                 mTitle = a.getString(attr);  
  30.                 break;  
  31.             case R.styleable.CustomImageView_titleTextColor:  
  32.                 mTextColor = a.getColor(attr, Color.BLACK);  
  33.                 break;  
  34.             case R.styleable.CustomImageView_titleTextSize:  
  35.                 mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,  
  36.                         16, getResources().getDisplayMetrics()));  
  37.                 break;  
  38.   
  39.             }  
  40.         }  
  41.         a.recycle();  
  42.         rect = new Rect();  
  43.         mPaint = new Paint();  
  44.         mTextBound = new Rect();  
  45.         mPaint.setTextSize(mTextSize);  
  46.         //Calculated the range of font descriptions needed  
  47.         mPaint.getTextBounds(mTitle, 0, mTitle.length(), mTextBound);  
  48.   
  49.     }  
/**
     * Initialize custom types that are specific to
     * 
     * @param context
     * @param attrs
     * @param defStyle
     */
    public CustomImageView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);

        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyle, 0);

        int n = a.getIndexCount();

        for (int i = 0; i < n; i++)
        {
            int attr = a.getIndex(i);

            switch (attr)
            {
            case R.styleable.CustomImageView_image:
                mImage = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0));
                break;
            case R.styleable.CustomImageView_imageScaleType:
                mImageScale = a.getInt(attr, 0);
                break;
            case R.styleable.CustomImageView_titleText:
                mTitle = a.getString(attr);
                break;
            case R.styleable.CustomImageView_titleTextColor:
                mTextColor = a.getColor(attr, Color.BLACK);
                break;
            case R.styleable.CustomImageView_titleTextSize:
                mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                        16, getResources().getDisplayMetrics()));
                break;

            }
        }
        a.recycle();
        rect = new Rect();
        mPaint = new Paint();
        mTextBound = new Rect();
        mPaint.setTextSize(mTextSize);
        // Calculated the range of font descriptions needed.
        mPaint.getTextBounds(mTitle, 0, mTitle.length(), mTextBound);

    }

3. Rewrite onMeasure

  1. @Override  
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
  3. {  
  4.     // super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  5.   
  6.     /** 
  7.      * Set width 
  8.      */  
  9.     int specMode = MeasureSpec.getMode(widthMeasureSpec);  
  10.     int specSize = MeasureSpec.getSize(widthMeasureSpec);  
  11.   
  12.     if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate  
  13.     {  
  14.         Log.e("xxx""EXACTLY");  
  15.         mWidth = specSize;  
  16.     } else  
  17.     {  
  18.         //Width determined by pictures  
  19.         int desireByImg = getPaddingLeft() + getPaddingRight() + mImage.getWidth();  
  20.         //Width determined by font  
  21.         int desireByTitle = getPaddingLeft() + getPaddingRight() + mTextBound.width();  
  22.   
  23.         if (specMode == MeasureSpec.AT_MOST)// wrap_content  
  24.         {  
  25.             int desire = Math.max(desireByImg, desireByTitle);  
  26.             mWidth = Math.min(desire, specSize);  
  27.             Log.e("xxx""AT_MOST");  
  28.         }  
  29.     }  
  30.   
  31.     /*** 
  32.      * Setting Height 
  33.      */  
  34.   
  35.     specMode = MeasureSpec.getMode(heightMeasureSpec);  
  36.     specSize = MeasureSpec.getSize(heightMeasureSpec);  
  37.     if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate  
  38.     {  
  39.         mHeight = specSize;  
  40.     } else  
  41.     {  
  42.         int desire = getPaddingTop() + getPaddingBottom() + mImage.getHeight() + mTextBound.height();  
  43.         if (specMode == MeasureSpec.AT_MOST)// wrap_content  
  44.         {  
  45.             mHeight = Math.min(desire, specSize);  
  46.         }  
  47.     }  
  48.     setMeasuredDimension(mWidth, mHeight);  
  49.   
  50. }  
   @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        /**
         * Set width
         */
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);

        if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate
        {
            Log.e("xxx", "EXACTLY");
            mWidth = specSize;
        } else
        {
            // Width determined by pictures
            int desireByImg = getPaddingLeft() + getPaddingRight() + mImage.getWidth();
            // Width determined by font size
            int desireByTitle = getPaddingLeft() + getPaddingRight() + mTextBound.width();

            if (specMode == MeasureSpec.AT_MOST)// wrap_content
            {
                int desire = Math.max(desireByImg, desireByTitle);
                mWidth = Math.min(desire, specSize);
                Log.e("xxx", "AT_MOST");
            }
        }

        /***
         * Setting Height
         */

        specMode = MeasureSpec.getMode(heightMeasureSpec);
        specSize = MeasureSpec.getSize(heightMeasureSpec);
        if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate
        {
            mHeight = specSize;
        } else
        {
            int desire = getPaddingTop() + getPaddingBottom() + mImage.getHeight() + mTextBound.height();
            if (specMode == MeasureSpec.AT_MOST)// wrap_content
            {
                mHeight = Math.min(desire, specSize);
            }
        }
        setMeasuredDimension(mWidth, mHeight);

    }

4. Rewrite onDraw

  1. @Override  
  2.     protected void onDraw(Canvas canvas)  
  3.     {  
  4.         // super.onDraw(canvas);  
  5.         /** 
  6.          * Frame 
  7.          */  
  8.         mPaint.setStrokeWidth(4);  
  9.         mPaint.setStyle(Paint.Style.STROKE);  
  10.         mPaint.setColor(Color.CYAN);  
  11.         canvas.drawRect(00, getMeasuredWidth(), getMeasuredHeight(), mPaint);  
  12.   
  13.         rect.left = getPaddingLeft();  
  14.         rect.right = mWidth - getPaddingRight();  
  15.         rect.top = getPaddingTop();  
  16.         rect.bottom = mHeight - getPaddingBottom();  
  17.   
  18.         mPaint.setColor(mTextColor);  
  19.         mPaint.setStyle(Style.FILL);  
  20.         /** 
  21.          * The width of the current setting is less than the required width of the font. Change the font to xxx. 
  22.          */  
  23.         if (mTextBound.width() > mWidth)  
  24.         {  
  25.             TextPaint paint = new TextPaint(mPaint);  
  26.             String msg = TextUtils.ellipsize(mTitle, paint, (float) mWidth - getPaddingLeft() - getPaddingRight(),  
  27.                     TextUtils.TruncateAt.END).toString();  
  28.             canvas.drawText(msg, getPaddingLeft(), mHeight - getPaddingBottom(), mPaint);  
  29.   
  30.         } else  
  31.         {  
  32.             //Normally, center the font  
  33.             canvas.drawText(mTitle, mWidth / 2 - mTextBound.width() * 1.0f / 2, mHeight - getPaddingBottom(), mPaint);  
  34.         }  
  35.   
  36.         //Quick Unuse  
  37.         rect.bottom -= mTextBound.height();  
  38.   
  39.         if (mImageScale == IMAGE_SCALE_FITXY)  
  40.         {  
  41.             canvas.drawBitmap(mImage, null, rect, mPaint);  
  42.         } else  
  43.         {  
  44.             //Calculate the middle rectangular range  
  45.             rect.left = mWidth / 2 - mImage.getWidth() / 2;  
  46.             rect.right = mWidth / 2 + mImage.getWidth() / 2;  
  47.             rect.top = (mHeight - mTextBound.height()) / 2 - mImage.getHeight() / 2;  
  48.             rect.bottom = (mHeight - mTextBound.height()) / 2 + mImage.getHeight() / 2;  
  49.   
  50.             canvas.drawBitmap(mImage, null, rect, mPaint);  
  51.         }  
  52.   
  53.     }  
@Override
    protected void onDraw(Canvas canvas)
    {
        // super.onDraw(canvas);
        /**
         * Border frame
         */
        mPaint.setStrokeWidth(4);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.CYAN);
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);

        rect.left = getPaddingLeft();
        rect.right = mWidth - getPaddingRight();
        rect.top = getPaddingTop();
        rect.bottom = mHeight - getPaddingBottom();

        mPaint.setColor(mTextColor);
        mPaint.setStyle(Style.FILL);
        /**
         * The width of the current setting is less than the required width of the font. Change the font to xxx.
         */
        if (mTextBound.width() > mWidth)
        {
            TextPaint paint = new TextPaint(mPaint);
            String msg = TextUtils.ellipsize(mTitle, paint, (float) mWidth - getPaddingLeft() - getPaddingRight(),
                    TextUtils.TruncateAt.END).toString();
            canvas.drawText(msg, getPaddingLeft(), mHeight - getPaddingBottom(), mPaint);

        } else
        {
            // Normally, center the font
            canvas.drawText(mTitle, mWidth / 2 - mTextBound.width() * 1.0f / 2, mHeight - getPaddingBottom(), mPaint);
        }

        // Quick Unuse
        rect.bottom -= mTextBound.height();

        if (mImageScale == IMAGE_SCALE_FITXY)
        {
            canvas.drawBitmap(mImage, null, rect, mPaint);
        } else
        {
            // Calculate the middle rectangular range
            rect.left = mWidth / 2 - mImage.getWidth() / 2;
            rect.right = mWidth / 2 + mImage.getWidth() / 2;
            rect.top = (mHeight - mTextBound.height()) / 2 - mImage.getHeight() / 2;
            rect.bottom = (mHeight - mTextBound.height()) / 2 + mImage.getHeight() / 2;

            canvas.drawBitmap(mImage, null, rect, mPaint);
        }

    }

Code, combined with comments and the use of the first View, should be able to understand, not understand the message. Here we introduce our custom View:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     xmlns:zhy="http://schemas.android.com/apk/res/com.zhy.customview02"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:orientation="vertical" >  
  7.   
  8.     <com.zhy.customview02.view.CustomImageView  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="wrap_content"  
  11.         android:layout_margin="10dp"  
  12.         android:padding="10dp"  
  13.         zhy:image="@drawable/ic_launcher"  
  14.         zhy:imageScaleType="center"  
  15.         zhy:titleText="hello andorid ! "  
  16.         zhy:titleTextColor="#ff0000"  
  17.         zhy:titleTextSize="30sp" />  
  18.   
  19.     <com.zhy.customview02.view.CustomImageView  
  20.         android:layout_width="100dp"  
  21.         android:layout_height="wrap_content"  
  22.         android:layout_margin="10dp"  
  23.         android:padding="10dp"  
  24.         zhy:image="@drawable/ic_launcher"  
  25.         zhy:imageScaleType="center"  
  26.         zhy:titleText="helloworldwelcome"  
  27.         zhy:titleTextColor="#00ff00"  
  28.         zhy:titleTextSize="20sp" />  
  29.   
  30.     <com.zhy.customview02.view.CustomImageView  
  31.         android:layout_width="wrap_content"  
  32.         android:layout_height="wrap_content"  
  33.         android:layout_margin="10dp"  
  34.         android:padding="10dp"  
  35.         zhy:image="@drawable/lmj"  
  36.         zhy:imageScaleType="center"  
  37.         zhy:titleText="Younger sister~"  
  38.         zhy:titleTextColor="#ff0000"  
  39.         zhy:titleTextSize="12sp" />  
  40.   
  41. </LinearLayout>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:zhy="http://schemas.android.com/apk/res/com.zhy.customview02"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.zhy.customview02.view.CustomImageView
        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:titleTextColor="#ff0000"
        zhy:titleTextSize="30sp" />

    <com.zhy.customview02.view.CustomImageView
        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:titleTextColor="#00ff00"
        zhy:titleTextSize="20sp" />

    <com.zhy.customview02.view.CustomImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:padding="10dp"
        zhy:image="@drawable/lmj"
        zhy:imageScaleType="center"
        zhy:titleText= "Mei Zi ~"
        zhy:titleTextColor="#ff0000"
        zhy:titleTextSize="12sp" />

</LinearLayout>

I intentionally let the display appear in 3 cases:

1. Font width is larger than picture, and View width is set to wrap_content

2. View width is set to an exact value, and font length is greater than this width.

3. The width of the picture is larger than that of the font, and the View width is set to wrap_content.

Look at the display effect:


Well, all three cases show good results.


Okay, that's it, you officers, leave a message, top one choke.~


Source Click Download




Posted by cauchyResidue on Sat, 22 Jun 2019 17:48:28 -0700