转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/43752383,本文出自:【张鸿洋的博客】

1、概述

Drawable在我们平时的开发中。基本都会用到,并且给大家很的实用。那么什么是Drawable呢?可以在canvas上绘制的一个玩意。并且相比于View,并不须要去考虑measure、layout,只只要去考虑怎样draw(canavs)。

当然了,对于Drawable传统的使用方法。大家肯定不陌生 。今天主要给大家带来下面几个Drawable的使用方法:

1、自己定义Drawable。相比View来说,Drawable属于轻量级的、使用也非常easy。

以后自己定义实现一个效果的时候。能够改变View first的思想。尝试下Drawable first。

2、自己定义状态,相信大家对于State Drawable都不陌生,可是有没有尝试过去自己定义一个状态呢?

3、利用Drawable提升我们的UI Perfermance 。 怎样利用Drawable去提升我们的UI的性能。

2、Drawable基本概念

普通情况下,除了直接使用放在Drawable下的图片,事实上的Drawable的使用方法都和xml相关。我们能够使用shape、layer-list等标签绘制一些背景。还能够通过selector标签定义View的状态的效果等。当然了基本每一个标签都相应于一个真正的实体类。关系例如以下:(图片来自:Cyril Mottier :master_android_drawables)

常见的使用方法这里就不举例了,以下開始看本文的重点。

2、自己定义Drawable

关于自己定义Drawable,能够通过写一个类,然后继承自Drawable , 类似于自己定义View,当然了自己定义Drawable的核心方法仅仅有一个,那就是draw。

那么自己定义Drawable究竟有什么实际的作用呢?能干什么呢?

相信大家对于圆角、圆形图片都不陌生。而且我以前写过通过自己定义View实现的方式,详细可參考:

Android BitmapShader
实战 实现圆形、圆角图片

Android
Xfermode 实战 实现圆形、圆角图片

那我今天要告诉你,不须要自己定义View。自己定义Drawable也能实现。并且更加简单、高效、使用范围更广(你能够作为不论什么View的背景)。

1、RoundImageDrawable

代码比較简单。以下看下RoundImageDrawable

[java] view
plain
 copy

  1. package com.zhy.view;
  2. import android.graphics.Bitmap;
  3. import android.graphics.BitmapShader;
  4. import android.graphics.Canvas;
  5. import android.graphics.ColorFilter;
  6. import android.graphics.Paint;
  7. import android.graphics.PixelFormat;
  8. import android.graphics.RectF;
  9. import android.graphics.Shader.TileMode;
  10. import android.graphics.drawable.Drawable;
  11. public class RoundImageDrawable extends Drawable
  12. {
  13. private Paint mPaint;
  14. private Bitmap mBitmap;
  15. private RectF rectF;
  16. public RoundImageDrawable(Bitmap bitmap)
  17. {
  18. mBitmap = bitmap;
  19. BitmapShader bitmapShader = new BitmapShader(bitmap, TileMode.CLAMP,
  20. TileMode.CLAMP);
  21. mPaint = new Paint();
  22. mPaint.setAntiAlias(true);
  23. mPaint.setShader(bitmapShader);
  24. }
  25. @Override
  26. public void setBounds(int left, int top, int right, int bottom)
  27. {
  28. super.setBounds(left, top, right, bottom);
  29. rectF = new RectF(left, top, right, bottom);
  30. }
  31. @Override
  32. public void draw(Canvas canvas)
  33. {
  34. canvas.drawRoundRect(rectF, 30, 30, mPaint);
  35. }
  36. @Override
  37. public int getIntrinsicWidth()
  38. {
  39. return mBitmap.getWidth();
  40. }
  41. @Override
  42. public int getIntrinsicHeight()
  43. {
  44. return mBitmap.getHeight();
  45. }
  46. @Override
  47. public void setAlpha(int alpha)
  48. {
  49. mPaint.setAlpha(alpha);
  50. }
  51. @Override
  52. public void setColorFilter(ColorFilter cf)
  53. {
  54. mPaint.setColorFilter(cf);
  55. }
  56. @Override
  57. public int getOpacity()
  58. {
  59. return PixelFormat.TRANSLUCENT;
  60. }
  61. }

核心代码就是draw了。but。我们仅仅须要一行~~~~setAlpha、setColorFilter、getOpacity、draw这几个方法是必须实现的,只是除了draw以为,其它都非常easy。

getIntrinsicWidth、getIntrinsicHeight主要是为了在View使用wrap_content的时候,提供一下尺寸,默觉得-1可不是我们希望的。

setBounds就是去设置下绘制的范围。

ok,圆角图片就这么实现了,easy 不~~

看下使用方法:

[java] view
plain
 copy

  1. Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
  2. R.drawable.mv);
  3. ImageView iv = (ImageView) findViewById(R.id.id_one);
  4. iv.setImageDrawable(new RoundImageDrawable(bitmap));

ok,贴一下我们的效果图。两个ImageView和一个TextView

能够看到,不只用于ImageView去实现圆角图片,而且能够作为不论什么View的背景。在ImageView中的拉伸的情况。配下ScaleType就可以。在其它View作为背景时,假设出现拉伸情况。请參考:Android
BitmapShader 实战 实现圆形、圆角图片
 。 足够具体了。

2、CircleImageDrawable

那么下来,我们再看看自己定义圆形Drawable的写法:

[java] view
plain
 copy

  1. package com.zhy.view;
  2. import android.graphics.Bitmap;
  3. import android.graphics.BitmapShader;
  4. import android.graphics.Canvas;
  5. import android.graphics.ColorFilter;
  6. import android.graphics.Paint;
  7. import android.graphics.PixelFormat;
  8. import android.graphics.RectF;
  9. import android.graphics.Shader.TileMode;
  10. import android.graphics.drawable.Drawable;
  11. public class CircleImageDrawable extends Drawable
  12. {
  13. private Paint mPaint;
  14. private int mWidth;
  15. private Bitmap mBitmap ;
  16. public CircleImageDrawable(Bitmap bitmap)
  17. {
  18. mBitmap = bitmap ;
  19. BitmapShader bitmapShader = new BitmapShader(bitmap, TileMode.CLAMP,
  20. TileMode.CLAMP);
  21. mPaint = new Paint();
  22. mPaint.setAntiAlias(true);
  23. mPaint.setShader(bitmapShader);
  24. mWidth = Math.min(mBitmap.getWidth(), mBitmap.getHeight());
  25. }
  26. @Override
  27. public void draw(Canvas canvas)
  28. {
  29. canvas.drawCircle(mWidth / 2, mWidth / 2, mWidth / 2, mPaint);
  30. }
  31. @Override
  32. public int getIntrinsicWidth()
  33. {
  34. return mWidth;
  35. }
  36. @Override
  37. public int getIntrinsicHeight()
  38. {
  39. return mWidth;
  40. }
  41. @Override
  42. public void setAlpha(int alpha)
  43. {
  44. mPaint.setAlpha(alpha);
  45. }
  46. @Override
  47. public void setColorFilter(ColorFilter cf)
  48. {
  49. mPaint.setColorFilter(cf);
  50. }
  51. @Override
  52. public int getOpacity()
  53. {
  54. return PixelFormat.TRANSLUCENT;
  55. }
  56. }

一样出奇的简单,再看一眼效果图:

ok。关于自己定义Drawable的样例over~~~接下来看自己定义状态的。

上述參考了:Romain Guy's Blog

3、自己定义Drawable State

关于Drawable State,state_pressed神马的,相信大家都掌握的特别熟练了。

那么接下来。我们有个需求,类似于邮箱,邮件以ListView形式展示。可是我们须要一个状态去标识出未读和已读:so,我们自己定义一个状态state_message_readed。

效果图:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG1qNjIzNTY1Nzkx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" style="border:none; max-width:602px; height:auto">

能够看到,假设是已读的邮件。我们的图标是打开状态,且有个淡红色的背景。那么怎样通过自己定义drawable state 实现呢?

自己定义drawable state 须要分为下面几个步骤:

1、res/values/新建一个xml文件:drawable_status.xml

[html] view
plain
 copy

  1. <?

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

  2. <resources>
  3. <declare-styleable name="MessageStatus">
  4. <attr name="state_message_readed" format="boolean" />
  5. </declare-styleable>
  6. </resources>

2、继承Item的容器

我们这里Item选择RelativeLayout实现,我们须要继承它,然后复写它的onCreateDrawableState方法。把我们自己定义的状态在合适的时候加入进去。

[java] view
plain
 copy

  1. package com.zhy.view;
  2. import com.zhy.sample.drawable.R;
  3. import android.content.Context;
  4. import android.util.AttributeSet;
  5. import android.widget.RelativeLayout;
  6. public class MessageListItem extends RelativeLayout
  7. {
  8. private static final int[] STATE_MESSAGE_READED = { R.attr.state_message_readed };
  9. private boolean mMessgeReaded = false;
  10. public MessageListItem(Context context, AttributeSet attrs)
  11. {
  12. super(context, attrs);
  13. }
  14. public void setMessageReaded(boolean readed)
  15. {
  16. if (this.mMessgeReaded != readed)
  17. {
  18. mMessgeReaded = readed;
  19. refreshDrawableState();
  20. }
  21. }
  22. @Override
  23. protected int[] onCreateDrawableState(int extraSpace)
  24. {
  25. if (mMessgeReaded)
  26. {
  27. final int[] drawableState = super
  28. .onCreateDrawableState(extraSpace + 1);
  29. mergeDrawableStates(drawableState, STATE_MESSAGE_READED);
  30. return drawableState;
  31. }
  32. return super.onCreateDrawableState(extraSpace);
  33. }
  34. }

代码不复杂,声明了一个STATE_MESSAGE_READED。然后在mMessgeReaded=true的情况下,通过onCreateDrawableState方法。增加我们自己定义的状态。

类似的代码,大家能够看看CompoundButton(CheckBox父类)的源代码。它有个checked状态:

[java] view
plain
 copy

  1. @Override
  2. protected int[] onCreateDrawableState(int extraSpace) {
  3. final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
  4. if (isChecked()) {
  5. mergeDrawableStates(drawableState, CHECKED_STATE_SET);
  6. }
  7. return drawableState;
  8. }

3、使用

布局文件:

[html] view
plain
 copy

  1. <com.zhy.view.MessageListItem xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="50dp"
  5. android:background="@drawable/message_item_bg" >
  6. <ImageView
  7. android:id="@+id/id_msg_item_icon"
  8. android:layout_width="30dp"
  9. android:src="@drawable/message_item_icon_bg"
  10. android:layout_height="wrap_content"
  11. android:duplicateParentState="true"
  12. android:layout_alignParentLeft="true"
  13. android:layout_centerVertical="true"
  14. />
  15. <TextView
  16. android:id="@+id/id_msg_item_text"
  17. android:layout_width="match_parent"
  18. android:layout_height="wrap_content"
  19. android:layout_centerVertical="true"
  20. android:layout_toRightOf="@id/id_msg_item_icon" />
  21. </com.zhy.view.MessageListItem>

非常easy,一个图标,一个文本;

Activity

[java] view
plain
 copy

  1. package com.zhy.sample.drawable;
  2. import com.zhy.view.MessageListItem;
  3. import android.app.ListActivity;
  4. import android.os.Bundle;
  5. import android.view.LayoutInflater;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8. import android.widget.ArrayAdapter;
  9. import android.widget.TextView;
  10. public class CustomStateActivity extends ListActivity
  11. {
  12. private Message[] messages = new Message[] {
  13. new Message("Gas bill overdue", true),
  14. new Message("Congratulations, you've won!", true),
  15. new Message("I love you!", false),
  16. new Message("Please reply!", false),
  17. new Message("You ignoring me?

    ", false),

  18. new Message("Not heard from you", false),
  19. new Message("Electricity bill", true),
  20. new Message("Gas bill", true), new Message("Holiday plans", false),
  21. new Message("Marketing stuff", false), };
  22. @Override
  23. protected void onCreate(Bundle savedInstanceState)
  24. {
  25. super.onCreate(savedInstanceState);
  26. getListView().setAdapter(new ArrayAdapter<Message>(this, -1, messages)
  27. {
  28. private LayoutInflater mInflater = LayoutInflater
  29. .from(getContext());
  30. @Override
  31. public View getView(int position, View convertView, ViewGroup parent)
  32. {
  33. if (convertView == null)
  34. {
  35. convertView = mInflater.inflate(R.layout.item_msg_list,
  36. parent, false);
  37. }
  38. MessageListItem messageListItem = (MessageListItem) convertView;
  39. TextView tv = (TextView) convertView
  40. .findViewById(R.id.id_msg_item_text);
  41. tv.setText(getItem(position).message);
  42. messageListItem.setMessageReaded(getItem(position).readed);
  43. return convertView;
  44. }
  45. });
  46. }
  47. }

代码非常easy。可是能够看到,我们须要在getView里面中去使用调用setMessageReaded方法,当然了其它的一些状态。肯定也要手动触发,比方在ACTION_DOWN中触发pressed等。

请勿纠结咋没有使用ViewHolder什么的。自己加入下即可。

本例參考自:Example from github

4、提升我们的UI Perfermance

如今大家越来越注重性能问题,事实上不是必需那么在乎,可是既然大家在乎了。这里通过Cyril Mottier :master_android_drawables ppt中的一个样例来说明假设利用Drawable来提升我们的UI的性能。

大家看这样一个效果图:

布局文件:

[html] view
plain
 copy

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:background="@color/app_background"
  6. android:padding="8dp" >
  7. <ImageView
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:layout_gravity="center"
  11. android:layout_marginBottom="24dp"
  12. android:src="@drawable/logo" />
  13. <LinearLayout
  14. android:layout_width="match_parent"
  15. android:layout_height="48dp"
  16. android:layout_gravity="bottom"
  17. android:orientation="horizontal" >
  18. <Button
  19. android:layout_width="0dp"
  20. android:layout_height="fill_parent"
  21. android:layout_weight="1"
  22. android:text="@string/sign_up" />
  23. <Button
  24. android:layout_width="0dp"
  25. android:layout_height="fill_parent"
  26. android:layout_weight="1"
  27. android:text="@string/sign_in" />
  28. </LinearLayout>
  29. </FrameLayout>

能够看到最外层是FrameLayout不过为了设置背景图和padding。这种布局相信非常多人也写过。

再看看这个布局作为APP启动时。用户的直观效果:

用户首先看到一个白板,然后显示出我们的页面。接下来,我们将利用Drawable改善我们的UI性能以及用户体验。

1、首先,我们去除我们最外层的FrameLayout。然后自己定义一个drawable的xml,叫做logo.xml

[html] view
plain
 copy

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
  3. <item>
  4. <shape android:shape="rectangle" >
  5. <solid android:color="@color/app_background" />
  6. </shape>
  7. </item>
  8. <item android:bottom="48dp">
  9. <bitmap
  10. android:gravity="center"
  11. android:src="@drawable/logo" />
  12. </item>
  13. </layer-list>

ok,这个drawable是设置了我们的背景和logo。

2、将其作为我们当前Activity的windowBackground

[html] view
plain
 copy

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <style
  4. name="Theme.Default.NoActionBar"
  5. parent="@android:style/Theme.Holo.Light.NoActionBar" >
  6. <item name="android:windowBackground">@drawable/login</item>
  7. </style>
  8. </resources>

3、设置到Activity上:

[html] view
plain
 copy

  1. <activity
  2. android:name="LoginActivity"
  3. android:theme="@style/Theme.Default.NoActionBar">

Ok,这样不仅最小化了我们的layout,如今我们的layout里面仅仅有一个LinearLayout和两个button;而且提升了用户体验,如今用户的直观效果时:

是不是体验好非常多,个人非常喜欢这个样例~~

ok,到此我们的文章就over了~~~大多数内容參考自一些牛人写的样例。样例还是棒棒哒,大家看完本文的同一时候。也能够去挖掘挖掘一些东西~~

源代码点击下载

Android Drawable 那些不为人知的高效使用方法的更多相关文章

  1. Android Drawable 那些不为人知的高效用法

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/43752383,本文出自:[张鸿洋的博客] 1.概述 Drawable在我们平时的 ...

  2. Android Drawable 与 LayerList综合汇总

    先看需求.要求这样的效果 上代码 <?xml version="1.0" encoding="utf-8"? > <layer-list xm ...

  3. Android开机启动Activity或者Service方法

    本文出自 “Bill_Hoo专栏” 博客,请务必保留此出处http://billhoo.blog.51cto.com/2337751/761230 这段时间在做Android的基础开发,现在有一需求是 ...

  4. Android 抗锯齿的两种方法

    Android 抗锯齿的两种方法 (其一:paint.setAntiAlias(ture);paint.setBitmapFilter(true))   在Android中,目前,我知道有两种出现锯齿 ...

  5. Android -- Drawable与Bitmap测试

    Drawable                                                                                 以下这个是测试加载10 ...

  6. ImageButton自定义按钮的按下效果的高效实现方法(非一般)

    通常情况下,我们可以采用如下方式实现: <?xml version="1.0" encoding="UTF-8"?> <selector xm ...

  7. (转)Android创建桌面快捷方式两种方法

    [IT168技术]Android在桌面上生成快捷方式有两种情况,一种是直接在桌面直接生成;一种是长按桌面,在弹出的快捷菜单中生成. 谈谈在桌面上直接生成.个人觉得这个比较爽快,既然都是快捷方式了干嘛还 ...

  8. Android Drawable绘图学习笔记(转)

    如何获取 res 中的资源 数据包package:android.content.res 主要类:Resources Android SDK中的简介:Class for accessing an ap ...

  9. Android开机启动Activity或者Service方法(转载)

    这段时间在做Android的基础开发,现在有一需求是开机启动,按照网上某些博文教程做了下,始终不成功,一开机总是提示所启动的应用程序意外终止,于是参考了Android SDK doc,终于解决问题,下 ...

随机推荐

  1. 局部变量,全局变量,extend,static

    main.c #include <stdio.h> #include "zs.h" /* 局部变量是定义在函数.代码块.函数形参列表.存储在栈中,从定义的那一行开始作用 ...

  2. nyoj--170--网络的可靠性(水题)

    网络的可靠性 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 A公司是全球依靠的互联网解决方案提供商,也是2010年世博会的高级赞助商.它将提供先进的网络协作技术,展示其 ...

  3. Bone Collector(hdoj--2602--01背包)

    Bone Collector Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  4. String不可变性

    今天分析一下String,String有很多实用的特性,比如说“不可变性”,是工程师精心设计的艺术品.用final就是拒绝继承,防止内部属性或方法被破坏. 一,什么是不可变? String不可变很简单 ...

  5. php手机号码验证正则表达式

    移动:134.135.136.137.138.139.150.151.152.157.158.159.182.183.184.187.188.178(4G).147(上网卡): 联通:130.131. ...

  6. 26. Remove Duplicates from Sorted Array[E]删除排序数组中的重复项

    题目 Given a sorted array nums, remove the duplicates in-place such that each element appear only once ...

  7. python学习-字符串 列表 元祖

    目录 Python翻转字符串(reverse string) 简单的步长为-1, 即字符串的翻转(常用) 递归反转 借用列表,使用reverse()方法 字符串常用操作 index split 切片 ...

  8. maven使用杂记

    maven test使用记录 运行指定的测试类:     >mvn test -Dtest=[ClassName] 运行测试类中指定的方法:(这个需要maven-surefire-plugin: ...

  9. C#解除某类警告。。。。。。。。。。

    C#预处理器指令取消不必要的警告 今天将自己写的一个类库生成一个DLL后,想把注释也加进去.... 方法:在属性->生成选项卡->XML文档文件(勾选)(生成的文件名不能修改,使用时必须跟 ...

  10. [hihicoder][Offer收割]编程练习赛47

    删除树节点 #pragma comment(linker, "/STACK:102400000,102400000") #include<stdio.h> #inclu ...