歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android打造帶透明圓弧的ImageView

這幾天因為項目需求,需要在ImageView上面疊加一層透明圓弧,並且在沿著圓弧的方向顯示相應的文字,效果如下圖所示:

拿到這個需求,首先想到的是自定義一個ImageView來實現此功能,即在onDraw()中繪制圓弧和文字。同時因為要保證圓弧的位置可以任意擺放,圓弧的顏色、透明度以及文字大小、顏色等都是可控的,所以增加了一些自定義屬性。實現代碼非常簡單,如下:

1.自定義ImageView:

package com.linuxidc.customviewsdemo.views.ArcImageView;

import Android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.ImageView;

import com.linuxidc.customviewsdemo.R;

/**
 * Description:A custom ImageView with circular arc and text
 * Author: XiaoYu
 * Date: 2016/5/10 13:55
 */
public class ArcImageView extends ImageView {
    /**
    * The default text size.
    */
    private final float DEFAULT_TEXT_SIZE = 20;
    /**
    * The default scale value which decides the width of arc.
    */
    private final float DEFAULT_SCALE = 0.5f;
    /**
    * The default transparency of arc.
    */
    private final int DEFAULT_ARC_ALPHA =100;
    /**
    * The default width of arc.
    */
    private final int DEFAULT_ARC_WIDTH =160;
    /**
    * The default angle that the arc starts with.
    */
    private final int DEFAULT_START_ANGLE = 180;
    /**
    * The default angle that the arc.
    */
    private final int DEFAULT_SWEEP_ANGLE = 90;
    /**
    * The default distance along the path to add to the text's starting position.
    */
    private final int DEFAULT_H_OFFSET = 100;
    /**
    * The default distance above(-) or below(+) the path to position the text.
    */
    private final int DEFAULT_V_OFFSET = 20;
    private Context mContext;
    /**
    * The text displayed on ImageView along arc.
    */
    private String mDrawStr;
    /**
    * The font size of text.
    */
    private float mTextSize = DEFAULT_TEXT_SIZE;
    /**
    * The scale value which decides the width of arc.
    */
    private float mScale = DEFAULT_SCALE;
    /**
    * The transparency of arc.
    */
    private int mArcAlpha = DEFAULT_ARC_ALPHA;
    /**
    * The width of arc.
    */
    private int mArcWidth = DEFAULT_ARC_WIDTH;
    /**
    * The start angle of angle.
    */
    private int mStartAngle = DEFAULT_START_ANGLE;
    /**
    * The swept angle of angle.
    */
    private int mSweepAngle = DEFAULT_SWEEP_ANGLE;
    /**
    * The default distance along the path to add to the text's starting position.
    */
    private float mHOffset = DEFAULT_H_OFFSET;
    /**
    * The default distance above(-) or below(+) the path to position the text.
    */
    private float mVOffset = DEFAULT_V_OFFSET;
    /**
    * The style of arc, all styles includes LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM, CENTER。
    * of course, you can add your own style according to your demands.
    */
    private int mDrawStyle;
    /**
    * The color of arc.
    */
    private int mArcColor;
    /**
    * The color of text.
    */
    private int mTextColor;

    public ArcImageView(Context context) {
        super(context);
        this.mContext = context;
    }

    public ArcImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        obtainAttributes(attrs);
    }

    public ArcImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        obtainAttributes(attrs);
    }

    /**
    * Set the text that will be drawn on arc.
    * @param drawStr the text content.
    */
    public void setDrawStr(String drawStr) {
        this.mDrawStr = drawStr;
        //refresh this view
        invalidate();
    }

    /**
    * Set the transparency of arc.
    * @param mArcAlpha the value of transparency.
    */
    public void setArcAlpha(int mArcAlpha) {
        this.mArcAlpha = mArcAlpha;
        //refresh this view
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //draw arc
        Paint arcPaint = new Paint();
        arcPaint.setStrokeWidth(mArcWidth);
        arcPaint.setStyle(Paint.Style.STROKE);
        arcPaint.setColor(mArcColor);
        arcPaint.setAlpha(mArcAlpha);
        int width = getWidth();
        int height = getHeight();
        float radius;
        if (width > height) {
            radius = mScale * height;
        } else {
            radius = mScale * width;
        }
        RectF oval = new RectF();

        int center_x = width;
        int center_y = height;

        switch (mDrawStyle) {
            case 0:
                center_x = 0;
                center_y = 0;
                mStartAngle = 90;
                mSweepAngle = -90;
                break;
            case 1:
                center_x = 0;
                center_y = height;
                mStartAngle = 270;
                mSweepAngle = 90;
                break;
            case 2:
                center_x = width;
                center_y = 0;
                mStartAngle = 180;
                mSweepAngle = -90;
                break;
            case 3:
                center_x = width;
                center_y = height;
                mStartAngle = 180;
                mSweepAngle = 90;
                break;
            case 4:
                center_x = width / 2;
                center_y = height / 2;
                mStartAngle = 270;
                mSweepAngle = 90;
                break;
        }
        float left = center_x - radius;
        float top = center_y - radius;
        float right = center_x + radius;
        float bottom = center_y + radius;
        oval.set(left, top, right, bottom);
        canvas.drawArc(oval, mStartAngle, mSweepAngle, false, arcPaint);

        //draw text
        Paint textPaint = new Paint();
        textPaint.setTextSize(mTextSize);
        textPaint.setStyle(Paint.Style.FILL);
        textPaint.setColor(mTextColor);
        Path path = new Path();
        path.addArc(oval, mStartAngle, mSweepAngle);
        canvas.drawTextOnPath(mDrawStr, path, mHOffset, mVOffset, textPaint);
    }

    /**
    * Obtain custom attributes that been defined in attrs.xml.
    * @param attrs A collection of attributes.
    */
    private void obtainAttributes(AttributeSet attrs) {
        TypedArray ta = mContext.obtainStyledAttributes(attrs, R.styleable.ArcImageView);
        mDrawStr = ta.getString(R.styleable.ArcImageView_drawStr);
        mTextSize = ta.getDimension(R.styleable.ArcImageView_textSize, DEFAULT_TEXT_SIZE);
        mArcAlpha = ta.getInteger(R.styleable.ArcImageView_arcAlpha, DEFAULT_ARC_ALPHA);
        mArcWidth = ta.getInteger(R.styleable.ArcImageView_arcWidth, DEFAULT_ARC_WIDTH);
        mStartAngle = ta.getInteger(R.styleable.ArcImageView_startAngle, DEFAULT_START_ANGLE);
        mSweepAngle = ta.getInteger(R.styleable.ArcImageView_startAngle, DEFAULT_SWEEP_ANGLE);
        mHOffset = ta.getInteger(R.styleable.ArcImageView_hOffset, DEFAULT_H_OFFSET);
        mVOffset = ta.getInteger(R.styleable.ArcImageView_vOffset, DEFAULT_V_OFFSET);
        mArcColor = ta.getColor(R.styleable.ArcImageView_arcColor, 0XCCCCCC);
        mTextColor = ta.getColor(R.styleable.ArcImageView_textColor, 0XFFFFFF);
        mDrawStyle = ta.getInt(R.styleable.ArcImageView_drawStyle, 0);
        ta.recycle();
    }
}

2.在values文件夾下的attrs.xml中自定義屬性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ArcImageView">
        <attr name="drawStr" format="string" />
        <attr name="textSize" format="dimension" />
        <attr name="arcAlpha" format="integer" />
        <attr name="arcWidth" format="integer" />
        <attr name="startAngle" format="integer" />
        <attr name="sweepAngle" format="integer" />
        <attr name="scale" format="float" />
        <attr name="hOffset" format="float" />
        <attr name="vOffset" format="float" />
        <attr name="drawStyle" format="enum">
            <enum name="LEFT_TOP" value="0" />
            <enum name="LEFT_BOTTOM" value="1" />
            <enum name="RIGHT_TOP" value="2" />
            <enum name="RIGHT_BOTTOM" value="3" />
            <enum name="CENTER" value="4" />
        </attr>
        <attr name="arcColor" format="color" />
        <attr name="textColor" format="color" />
    </declare-styleable>
</resources>

3.在MainActivity調用ArcImageView,實現代碼如下:

package com.linuxidc.customviewsdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

import com.linuxidc.customviewsdemo.views.ArcImageView.ArcImageView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private ArcImageView aiv_one;
    private ArcImageView aiv_two;
    private ArcImageView aiv_three;
    private ArcImageView aiv_four;
    private Button btn_another_one;
    private int mGroup = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        aiv_one = (ArcImageView) findViewById(R.id.aiv_one);
        aiv_one.setArcAlpha(180);
        aiv_two = (ArcImageView) findViewById(R.id.aiv_two);
        aiv_two.setArcAlpha(180);
        aiv_three = (ArcImageView) findViewById(R.id.aiv_three);
        aiv_three.setArcAlpha(180);
        aiv_four = (ArcImageView) findViewById(R.id.aiv_four);
        aiv_four.setArcAlpha(180);
        btn_another_one = (Button) findViewById(R.id.btn_another_one);
        btn_another_one.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_another_one:
                if (mGroup == 1) {
                    aiv_one.setDrawStr("蘋果");
                    aiv_one.setBackgroundResource(R.drawable.apple);
                    aiv_two.setDrawStr("柚子");
                    aiv_two.setBackgroundResource(R.drawable.pineapple);
                    aiv_three.setDrawStr("香蕉");
                    aiv_three.setBackgroundResource(R.drawable.banana);
                    aiv_four.setDrawStr("菠蘿");
                    aiv_four.setBackgroundResource(R.drawable.pineapple);
                    mGroup = 2;
                } else {
                    aiv_one.setDrawStr("牛排");
                    aiv_one.setBackgroundResource(R.drawable.steak);
                    aiv_two.setDrawStr("海鮮");
                    aiv_two.setBackgroundResource(R.drawable.seafood);
                    aiv_three.setDrawStr("奶酪");
                    aiv_three.setBackgroundResource(R.drawable.cheese);
                    aiv_four.setDrawStr("燒烤");
                    aiv_four.setBackgroundResource(R.drawable.barbecue);
                    mGroup = 1;
                }
                break;
        }
    }
}

4.MainActivity的布局文件如下:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="100dp"
    android:layout_marginBottom="100dp"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btn_another_one"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="換一組" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal" >

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent" >

            <com.linuxidc.customviewsdemo.views.ArcImageView.ArcImageView
                android:id="@+id/aiv_one"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/steak"
                custom:draw
                custom:drawStr="牛排"
                custom:arcAlpha="100"
                custom:arcColor="@color/gray"
                custom:textColor="@color/black"
                custom:textSize="20sp" />
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent" >

            <com.linuxidc.customviewsdemo.views.ArcImageView.ArcImageView
                android:id="@+id/aiv_two"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/seafood"
                custom:draw
                custom:drawStr="海鮮"
                custom:arcAlpha="100"
                custom:arcColor="@color/gray"
                custom:textColor="@color/black"
                custom:textSize="20sp" />

        </RelativeLayout>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal" >

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent" >

            <com.linuxidc.customviewsdemo.views.ArcImageView.ArcImageView
                android:id="@+id/aiv_three"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/cheese"
                custom:draw
                custom:drawStr="奶酪"
                custom:arcAlpha="100"
                custom:arcColor="@color/gray"
                custom:textColor="@color/black"
                custom:textSize="20sp" />
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent" >

            <com.linuxidc.customviewsdemo.views.ArcImageView.ArcImageView
                android:id="@+id/aiv_four"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/barbecue"
                custom:draw
                custom:drawStr="燒烤"
                custom:arcAlpha="100"
                custom:arcColor="@color/gray"
                custom:textColor="@color/black"
                custom:textSize="20sp" />

        </RelativeLayout>
    </LinearLayout>
</LinearLayout>

注意,在布局文件中引入自定義屬性時需要加入一行代碼:xmlns:custom="http://schemas.android.com/apk/res-auto"。

好了,需求搞定,剩下的就是搬到實際的項目當中去了。實現效果如下:

總結一下,自定義View一般就是通過重寫onDraw、onMeasure()、onLayout()等方法來進行測量、繪制,繪制的時候一般會用到Canvas、Paint、Bitmap等類,測量和繪制的過程其實就是對現實生活中繪圖工作的抽象和實現,我們利用面向對象的思想將畫板、畫紙、畫筆等工具以及繪畫的動作用一行行代碼加以描述就OK啦!

由於實現過程比較簡單,我就不貼源碼了,大家如果對2D繪圖還不是很了解,可以去搜一下相關資料或查閱相關書籍!

更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11

Copyright © Linux教程網 All Rights Reserved