Android App中自定义View视图的实例教程

一、基础
很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章。先总结下自定义View的步骤:
1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
3、重写onMesure
4、重写onDraw
我把3用[]标出了,所以说3不一定是必须的,当然了大部分情况下还是需要重写的。

1、自定义View的属性,首先在res/values/  下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。

<?xml version="1.0" encoding="utf-8"?>
<resources> 

  <attr name="titleText" format="string" />
  <attr name="titleTextColor" format="color" />
  <attr name="titleTextSize" format="dimension" /> 

  <declare-styleable name="CustomTitleView">
    <attr name="titleText" />
    <attr name="titleTextColor" />
    <attr name="titleTextSize" />
  </declare-styleable> 

</resources>

我们定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型:
一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;不清楚的可以google一把。
然后在布局中声明我们的自定义View

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01"
  android:layout_width="match_parent"
  android:layout_height="match_parent" > 

  <com.example.customview01.view.CustomTitleView
    android:layout_width="200dp"
    android:layout_height="100dp"
    custom:titleText="3712"
    custom:titleTextColor="#ff0000"
    custom:titleTextSize="40sp" /> 

</RelativeLayout>

一定要引入 xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01"我们的命名空间,后面的包路径指的是项目的package

2、在View的构造方法中,获得我们的自定义的样式

/**
   * 文本
   */
  private String mTitleText;
  /**
   * 文本的颜色
   */
  private int mTitleTextColor;
  /**
   * 文本的大小
   */
  private int mTitleTextSize; 

  /**
   * 绘制时控制文本绘制的范围
   */
  private Rect mBound;
  private Paint mPaint; 

  public CustomTitleView(Context context, AttributeSet attrs)
  {
    this(context, attrs, 0);
  } 

  public CustomTitleView(Context context)
  {
    this(context, null);
  } 

  /**
   * 获得我自定义的样式属性
   *
   * @param context
   * @param attrs
   * @param defStyle
   */
  public CustomTitleView(Context context, AttributeSet attrs, int defStyle)
  {
    super(context, attrs, defStyle);
    /**
     * 获得我们所定义的自定义样式属性
     */
    TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0);
    int n = a.getIndexCount();
    for (int i = 0; i < n; i++)
    {
      int attr = a.getIndex(i);
      switch (attr)
      {
      case R.styleable.CustomTitleView_titleText:
        mTitleText = a.getString(attr);
        break;
      case R.styleable.CustomTitleView_titleTextColor:
        // 默认颜色设置为黑色
        mTitleTextColor = a.getColor(attr, Color.BLACK);
        break;
      case R.styleable.CustomTitleView_titleTextSize:
        // 默认设置为16sp,TypeValue也可以把sp转化为px
        mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
        break; 

      } 

    }
    a.recycle(); 

    /**
     * 获得绘制文本的宽和高
     */
    mPaint = new Paint();
    mPaint.setTextSize(mTitleTextSize);
    // mPaint.setColor(mTitleTextColor);
    mBound = new Rect();
    mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound); 

  }

我们重写了3个构造方法,默认的布局文件调用的是两个参数的构造方法,所以记得让所有的构造调用我们的三个参数的构造,我们在三个参数的构造中获得自定义属性。
3、我们重写onDraw,onMesure调用系统提供的:

@Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
  {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  } 

  @Override
  protected void onDraw(Canvas canvas)
  {
    mPaint.setColor(Color.YELLOW);
    canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); 

    mPaint.setColor(mTitleTextColor);
    canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
  }

此时的效果是:

是不是觉得还不错,基本已经实现了自定义View。但是此时如果我们把布局文件的宽和高写成wrap_content,会发现效果并不是我们的预期:

系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。
所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”:
重写之前先了解MeasureSpec的specMode,一共三种类型:
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用
下面是我们重写onMeasure代码:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
  int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  int heightSize = MeasureSpec.getSize(heightMeasureSpec);
  int width;
  int height ;
  if (widthMode == MeasureSpec.EXACTLY)
  {
    width = widthSize;
  } else
  {
    mPaint.setTextSize(mTitleTextSize);
    mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);
    float textWidth = mBounds.width();
    int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
    width = desired;
  } 

  if (heightMode == MeasureSpec.EXACTLY)
  {
    height = heightSize;
  } else
  {
    mPaint.setTextSize(mTitleTextSize);
    mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);
    float textHeight = mBounds.height();
    int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());
    height = desired;
  } 

  setMeasuredDimension(width, height);
}

现在我们修改下布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01"
  android:layout_width="match_parent"
  android:layout_height="match_parent" > 

  <com.example.customview01.view.CustomTitleView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    custom:titleText="3712"
    android:padding="10dp"
    custom:titleTextColor="#ff0000"
    android:layout_centerInParent="true"
    custom:titleTextSize="40sp" /> 

</RelativeLayout>

现在的效果是:

完全复合我们的预期,现在我们可以对高度、宽度进行随便的设置了,基本可以满足我们的需求。
当然了,这样下来我们这个自定义View与TextView相比岂不是没什么优势,所有我们觉得给自定义View添加一个事件:
在构造中添加:

this.setOnClickListener(new OnClickListener()
    { 

      @Override
      public void onClick(View v)
      {
        mTitleText = randomText();
        postInvalidate();
      } 

    }); 

private String randomText()
  {
    Random random = new Random();
    Set<Integer> set = new HashSet<Integer>();
    while (set.size() < 4)
    {
      int randomInt = random.nextInt(10);
      set.add(randomInt);
    }
    StringBuffer sb = new StringBuffer();
    for (Integer i : set)
    {
      sb.append("" + i);
    } 

    return sb.toString();
  }

下面再来运行:

我们添加了一个点击事件,每次让它随机生成一个4位的随机数,有兴趣的可以在onDraw中添加一点噪点,然后改写为验证码,是不是感觉很不错。

进阶

前面已经介绍过一个自定义View的基础的例子,下面给大家带来一个稍微复杂点的例子。
自定义View显示一张图片,下面包含图片的文本介绍,类似相片介绍什么的,不过不重要,主要是学习自定义View的用法么。
直接切入正题:
1、在res/values/attr.xml

<?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、在构造中获得我们的自定义属性:

/**
   * 初始化所特有自定义类型
   *
   * @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);
    // 计算了描绘字体需要的范围
    mPaint.getTextBounds(mTitle, 0, mTitle.length(), mTextBound); 

  }

3、重写onMeasure

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
  // super.onMeasure(widthMeasureSpec, heightMeasureSpec); 

  /**
   * 设置宽度
   */
  int specMode = MeasureSpec.getMode(widthMeasureSpec);
  int specSize = MeasureSpec.getSize(widthMeasureSpec); 

  if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate
  {
    Log.e("xxx", "EXACTLY");
    mWidth = specSize;
  } else
  {
    // 由图片决定的宽
    int desireByImg = getPaddingLeft() + getPaddingRight() + mImage.getWidth();
    // 由字体决定的宽
    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");
    }
  } 

  /***
   * 设置高度
   */ 

  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、重写onDraw

@Override
  protected void onDraw(Canvas canvas)
  {
    // super.onDraw(canvas);
    /**
     * 边框
     */
    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);
    /**
     * 当前设置的宽度小于字体需要的宽度,将字体改为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
    {
      //正常情况,将字体居中
      canvas.drawText(mTitle, mWidth / 2 - mTextBound.width() * 1.0f / 2, mHeight - getPaddingBottom(), mPaint);
    } 

    //取消使用掉的快
    rect.bottom -= mTextBound.height(); 

    if (mImageScale == IMAGE_SCALE_FITXY)
    {
      canvas.drawBitmap(mImage, null, rect, mPaint);
    } else
    {
      //计算居中的矩形范围
      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);
    } 

  }

代码,结合注释和基础部分View的使用,应该可以看懂,不明白的留言。下面我们引入我们的自定义View:

<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="妹子~"
    zhy:titleTextColor="#ff0000"
    zhy:titleTextSize="12sp" /> 

</LinearLayout>

我特意让显示出现3中情况:
1、字体的宽度大于图片,且View宽度设置为wrap_content
2、View宽度设置为精确值,字体的长度大于此宽度
3、图片的宽度大于字体,且View宽度设置为wrap_content
看看显示效果:

怎么样,对于这三种情况所展示的效果都还不错吧。

(0)

相关推荐

  • Android开发之自定义View(视图)用法详解

    本文实例讲述了Android开发之自定义View(视图)用法.分享给大家供大家参考,具体如下: View类是Android的一个超类,这个类几乎包含了所有的屏幕类型.每一个View都有一个用于绘图的画布,这个画布可以进行任意扩展.在游戏开发中往往需要自定义视图(View),这个画布的功能更能满足我们在游戏开发中的需要.在Android中,任何一个View类都只需重写onDraw 方法来实现界面显示,自定义的视图可以是复杂的3D实现,也可以是非常简单的文本形式等. 为了实现自定义View,需要创建

  • Android 获得View宽高的几种方式总结

    <Android开发艺术探索>笔记: 在Activity的onCreate()或者onResume()中去获得View的高度的时候不能正确获得宽度和高度信息,这是因为 View的measure过程和Activity的生命周期不是同步执行的,因此无法保证Activity执行了onCreate onStart onResume时,某个View已经测量完毕了,如果还没有测量完,那么获得的宽高就是0.可以通过下面几种方式来获得: 1.onWindowFocusChanged onWindowFocus

  • Android视图控件架构分析之View、ViewGroup

    在Android中,视图控件大致被分为两类,即ViewGroup和View,ViewGroup控件作为父控件,包含并管理着子View,通过ViewGroup和View便形成了控件树,各个ViewGoup对象和View对象就是控件树中的节点.在控件树中,以树的深度来遍历查找对应的控件元素,同时,上层控件负责子控件的测量与绘制,并传递交互事件. Android控件树: AndroidUI界面架构图: 一.测量View的工具类:MeasureSpec 1.MeasureSpec包含了测量的模式和测量的

  • Android中RecyclerView的item宽高问题详解

    前言 本文主要给大家介绍了关于Android中RecyclerView的item宽高问题的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 在创建viewholder传入的View时,如果不指定其viewgroup,就会出现宽高只包裹显示内容的问题. View view = LayoutInflater.from(context).inflate(R.layout.test_test,null); 上面的做法就会出问题 改成这样就可以正常显示设置的宽高 View vie

  • Android获取屏幕或View宽度和高度的方法

    本文实例讲述了Android获取屏幕或View宽度和高度的方法.分享给大家供大家参考,具体如下: 在Activity中获取屏幕的高度和宽度 Display display=getWindowManager().getDefaultDisplay(); int width=display.getWidth(); int height=display.getHeight(); 在重写ViewGroup中获取屏幕的有效宽度和高度在OnMesure方法中 protected void onMeasure

  • 4种Android获取View宽高的方式

    有时我们会有基于这样的需求,当Activity创建时,需要获取某个View的宽高,然后进行相应的操作,但是我们在onCreate,onStart中获取View的大小,获取到的值都是0,只是由于View的绘制工程还未完成,和在onCreate中弹出Dialog或者PopupWindow会报一个Activity not running原理类似. 接下来就为大家介绍几种获取View宽高的方法: 第一种方式:重写Activity中的onWindowFocusChanged,当Activity获取到焦点的

  • Android开发中获取View视图宽与高的常用方法小结

    本文实例讲述了Android开发中获取View视图宽与高的常用方法.分享给大家供大家参考,具体如下: 一.根据WindowManager管理器获得 1)这两种方法在屏幕未显示的时候,还是处于0的状态,即要在setContentView调用之后才有效. 2)Activity必须如此设置才能获得view的宽高 //设置为无标题 requestWindowFeature(Window.FEATURE_NO_TITLE); //设置为全屏模式getWindow().setFlags(WindowMana

  • Android ImageView 固定宽高比例的实现方法

    Android ImageView 固定宽高比例的实现方法 本文主要介绍 ImageView 固定宽高比例, 方法一:设置 adjustViewBounds="true", 方法二:使用 Universal-Image-Loader 图片缓存类,需要注意的是方法二和方法一同时使用导致设置无效. 方法一:设置 adjustViewBounds="true" <ImageView android:id="@+id/img_banner" and

  • Android视图的绘制流程(上) View的测量

    综述 View的绘制流程可以分为三大步,它们分别是measure,layout和draw过程.measure表示View的测量过程,用于测量View的宽度和高度:layout用于确定View在父容器的位置:draw则是负责将View绘制到屏幕中.下面主要来看一下View的Measure过程. 测量过程 View的绘制流程是从ViewRoot的performTraversals方法开始的,ViewRoot对应ViewRootImpl类.ViewRoot在performTraversals中会调用p

  • Android App中自定义View视图的实例教程

    一.基础 很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章.先总结下自定义View的步骤: 1.自定义View的属性 2.在View的构造方法中获得我们自定义的属性 3.重写onMesure 4.重写onDraw 我把3用[]标出了,所以说3不一定是必须的,当然了大部分情况下还是需要重写的. 1.自定义View的属性,首先在res/values/  下建立一个attrs.xm

  • Android应用开发中自定义ViewGroup视图容器的教程

    一.概述 在写代码之前,我必须得问几个问题: 1.ViewGroup的职责是啥? ViewGroup相当于一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属性,都是为用于告诉容器的),我们的宽度(layout_width).高度(layout_height).对齐方式(layout_gravity)等:当然还有margin等:于是乎,ViewGroup的职能为:给childView计算出建议的宽和高和测量模式 :决定childView的位置:为什么只是

  • Android编程中自定义dialog用法实例

    本文实例讲述了Android编程中自定义dialog用法.分享给大家供大家参考,具体如下: dialog是android中提供的一组弹出提示框,非常好用,可是它的样式是一个定式,有时候我们需求定义一些自己的样式 1.定义一个样式文件,此文件继承自Theme.Dialog,在style.xml文件中建立一个自己的样式 <style name="addNoteType_error_Dialog" parent="@android:Theme.Dialog">

  • Android中自定义view实现侧滑效果

    效果图: 看网上的都是两个view拼接,默认右侧的不显示,水平移动的时候把右侧的view显示出来.但是看最新版QQ上的效果不是这样的,但给人的感觉却很好,所以献丑来一发比较高仿的. 知识点: 1.ViewDragHelper 的用法: 2.滑动冲突的解决: 3.自定义viewgroup. ViewDragHelper 出来已经比较久了 相信大家都比较熟悉,不熟悉的话google一大把这里主要简单用一下它的几个方法 1.tryCaptureView(View child, int pointerI

  • Android 自定义View之倒计时实例代码

    Android 自定义View之倒计时实例代码 需求: 大多数app在注册的时候,都有一个获取验证码的按钮,点击后,访问接口,最终用户会收到短信验证码.为了不多次写这个获取验证码的接口,下面将它自定义成一个view,方便使用. 分析一下,这是一个TextView,点击的时候变色,不能再点击,同时里面的倒计时开始显示.那么就有了下面的代码 代码: /** * 通过selector选择器来改变背景,其中倒计时运行时为android:state_enabled="true", * 不显示倒计

  • android 实现APP中改变头像图片的实例代码

    具体代码如下所示: package com.example.studyapplication.fragment; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory

  • Android开发使用自定义View将圆角矩形绘制在Canvas上的方法

    本文实例讲述了Android开发使用自定义View将圆角矩形绘制在Canvas上的方法.分享给大家供大家参考,具体如下: 前几天,公司一个项目中,头像图片需要添加圆角,这样UI效果会更好看,于是写了一个小的demo进行圆角的定义,该处主要是使用BitmapShader进行了渲染(如果要将一张图片裁剪成椭圆或圆形显示在屏幕上,也可以使用BitmapShader来完成). BitmapShader类完成渲染图片的基本步骤如下: 1.创建BitmapShader类的对象 /** * Call this

  • Android编程基于自定义view实现公章效果示例【附源码下载】

    本文实例讲述了Android编程基于自定义view实现公章效果.分享给大家供大家参考,具体如下: 上次去一个公司面试,面试官问了一个题,怎么用android的自定义view实现一个公章的效果,据说这是华为之前的面试题,我想了下,要是公章的效果,最外层是一个圆,里面是一个五角星,但是这文字怎么画呢,比较难搞,后来回来看了下java的api,发现人家的Path里面本来就提供了这么一个方法: public void addArc(RectF oval, float startAngle, float

随机推荐