Android开发技巧——使用Drawable实现小红点
2017-01-05 11:13
120 查看
在产品的设计中,总难免需要我们开发去实现各种各样的小红点,小红点,小红点。
通常,我们可能会这样做:
用一个View实现小红点,放在相对布局里,设置好内边距或外边距,让它位于图片的右上角。
或者是给图片套一个相对布局,设置好图片的外边距,然后把表示小红点的View放在这个相对布局里面的右上角。
这个应该是最简洁直观的实现方法。然而,它也有它的局限之处。
比如在我这次的开发当中,一开始只是需要实现如下的界面:
为了省事,我当然是直接用AndroidStudio提供的侧滑菜单的模板了,然后再稍作改动,设置一下导航栏的按钮图标和内容布局,写一下侧滑Header的布局,再写一下侧滑菜单的menu.xml文件,就完成了。
在完成了这些,其他功能开发到一半的时候才说要在这两个界面增加小红点。然而,我们的标题栏用的是toolbar,默认对于这个导航图标的设置是只能通过
另外,我们的侧滑菜单,也是通过在menu资源文件夹里通过如下方式来定义的:
它也只是指定图标和文字,并不能指定小红点。
如果说只为实现这两个小红点,就要自己去做toolbar及侧滑菜单的自定义实现,从时间成本上考虑,眼前都要过年了,肯定是难以接受的。好在发现它们两个都可以获取及设置drawable,那我们就有办法了。
思路如下,实现一个Drawable,在它里面套一层原来的Drawable,并且绘制出我们的小红点。好像很简单?support库里的
接下来思考一下我们要实现的具体功能。
首先,前面的小红点,如果你注意观察会发现,它们的位置不是都以图片的右上角为中心点的。
比如导航栏的小红点左边缘是与图标右边缘对齐的:
消息中心是小红点的右边缘与图标的右边缘对齐的:
另外,我们还需要一个开关,设置是否显示小红点。
最终,代码实现如下:
下面就可以使用它来给我们的导航栏图标设置小红点了。设置导航栏图标的代码改为如下:
然后我们可以把这个icon给保存到成员变量里,通过调用这个drawable的
然后我们还要获取侧滑菜单消息中心的drawable,给它也设置一下:
通常,我们可能会这样做:
用一个View实现小红点,放在相对布局里,设置好内边距或外边距,让它位于图片的右上角。
或者是给图片套一个相对布局,设置好图片的外边距,然后把表示小红点的View放在这个相对布局里面的右上角。
这个应该是最简洁直观的实现方法。然而,它也有它的局限之处。
比如在我这次的开发当中,一开始只是需要实现如下的界面:
为了省事,我当然是直接用AndroidStudio提供的侧滑菜单的模板了,然后再稍作改动,设置一下导航栏的按钮图标和内容布局,写一下侧滑Header的布局,再写一下侧滑菜单的menu.xml文件,就完成了。
在完成了这些,其他功能开发到一半的时候才说要在这两个界面增加小红点。然而,我们的标题栏用的是toolbar,默认对于这个导航图标的设置是只能通过
toolbar.setNavigationIcon(Drawable icon)或
toolbar.setNavigationIcon(int resId)来设置一个图片上去的,并不能在里面添加一个小红点的View。
另外,我们的侧滑菜单,也是通过在menu资源文件夹里通过如下方式来定义的:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/nav_wallet" android:icon="@drawable/icon_menu_wallet" android:title="@string/menu_my_wallet"/> <item android:id="@+id/nav_plate" android:icon="@drawable/icon_menu_plate" android:title="@string/menu_my_vehicle"/> <!--其他菜单项略--> </menu>
它也只是指定图标和文字,并不能指定小红点。
如果说只为实现这两个小红点,就要自己去做toolbar及侧滑菜单的自定义实现,从时间成本上考虑,眼前都要过年了,肯定是难以接受的。好在发现它们两个都可以获取及设置drawable,那我们就有办法了。
思路如下,实现一个Drawable,在它里面套一层原来的Drawable,并且绘制出我们的小红点。好像很简单?support库里的
TintAwareDrawable就是这么做的。
接下来思考一下我们要实现的具体功能。
首先,前面的小红点,如果你注意观察会发现,它们的位置不是都以图片的右上角为中心点的。
比如导航栏的小红点左边缘是与图标右边缘对齐的:
消息中心是小红点的右边缘与图标的右边缘对齐的:
另外,我们还需要一个开关,设置是否显示小红点。
最终,代码实现如下:
import android.content.Context; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.res.ResourcesCompat; import android.view.Gravity; public class RedPointDrawable extends Drawable { private Drawable mDrawable; private boolean mShowRedPoint; private Paint mPaint; private int mRadius; private int mGravity = Gravity.CENTER; public RedPointDrawable(Context context, Drawable origin) { mDrawable = origin;// 原来的drawable mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); mPaint.setColor(Color.RED); mRadius = context.getResources().getDimensionPixelSize(R.dimen.red_point_radius_small);//小红点半径 } public void setColor(int color) { mPaint.setColor(color); } public void setShowRedPoint(boolean showRedPoint) { mShowRedPoint = showRedPoint; invalidateSelf(); } public void setRadius(int radius) { this.mRadius = radius; } public void setGravity(int gravity) { this.mGravity = gravity; } @Override public void draw(@NonNull Canvas canvas) mDrawable.draw(canvas);//先绘制原图标 if (mShowRedPoint) { // 获取原图标的右上角坐标 int cx = getBounds().right; int cy = getBounds().top; // 计算我们的小红点的坐标 if ((Gravity.LEFT & mGravity) == Gravity.LEFT) { cx -= mRadius; } else if ((Gravity.RIGHT & mGravity) == Gravity.RIGHT) { cx += mRadius; } if ((Gravity.TOP & mGravity) == Gravity.TOP) { cy -= mRadius; } else if ((Gravity.BOTTOM & mGravity) == Gravity.BOTTOM) { cy += mRadius; } canvas.drawCircle(cx, cy, mRadius, mPaint);//绘制小红点 } } @Override public void setAlpha(@IntRange(from = 0, to = 255) int alpha) { mDrawable.setAlpha(alpha); } @Override public void setColorFilter(@Nullable ColorFilter colorFilter) { mDrawable.setColorFilter(colorFilter); } @Override public int getOpacity() { return mDrawable.getOpacity(); } @Override public int getIntrinsicHeight() { return mDrawable.getIntrinsicHeight();//它的高度使用原来的高度 } @Override public int getIntrinsicWidth() { return mDrawable.getIntrinsicWidth();//它的宽度使用原来的宽度 } @Override public void setBounds(@NonNull Rect bounds) { super.setBounds(bounds); mDrawable.setBounds(bounds); } @Override public void setBounds(int left, int top, int right, int bottom) { super.setBounds(left, top, right, bottom); mDrawable.setBounds(left, top, right, bottom); } public static RedPointDrawable wrap(Context context, Drawable drawable) { // 把原来的Drawable包装为一个小红点的Drawable if (drawable instanceof RedPointDrawable) { return (RedPointDrawable) drawable; } return new RedPointDrawable(context, drawable); } }
下面就可以使用它来给我们的导航栏图标设置小红点了。设置导航栏图标的代码改为如下:
final RedPointDrawable icon = new RedPointDrawable(this, ResourcesCompat.getDrawable(getResources(), R.drawable.icon_user, null)); icon.setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL); toolbar.setNavigationIcon(icon); // 把drawable添加到我们的成员变量中去,以便后面直接对它进行设置 //mRedPointView.addRedPointDrawable(redPointDrawable);
然后我们可以把这个icon给保存到成员变量里,通过调用这个drawable的
setShowRedPoint(boolean)就可以设置显示及隐藏了。
然后我们还要获取侧滑菜单消息中心的drawable,给它也设置一下:
private void initForMessageCenterIcon(NavigationView navigationView) { Menu menu = navigationView.getMenu(); int size = menu.size(); for (int i = 0; i < size; i++) { MenuItem item = menu.getItem(i); if (item.getItemId() == R.id.nav_message) { RedPointDrawable redPointDrawable = RedPointDrawable.wrap(this, item.getIcon()); redPointDrawable.setGravity(Gravity.LEFT); item.setIcon(redPointDrawable); // 把drawable添加到我们的成员变量中去,以便后面直接对它进行设置 //mRedPointView.addRedPointDrawable(redPointDrawable); } } }
相关文章推荐
- Android开发技巧——使用Drawable实现小红点
- android 开发技巧(1)--使用 weight 属性实现视图的居中显示
- Android开发技巧——使用RecyclerView实现分组列表
- Android开发技巧——使用PopupWindow实现弹出菜单
- Android开发技巧——使用PopupWindow实现弹出菜单
- Android开发技巧——使用Dialog实现仿QQ的ActionSheet菜单
- Android开发技巧——使用PopupWindow实现弹出菜单
- Android开发技巧——使用Dialog实现仿QQ的ActionSheet菜单
- Windows Phone 7开发技巧【2】——使用ZXing库实现一维/二维条码扫描
- Android游戏开发之使用AnimationDrable实现Frame动画(三十一)
- Android开发(10)使用SQLiteDatabase操作SQLite数据库实现增删改查(源码)
- android游戏开发框架libgdx的使用(二十三)—使用Universal Tween Engine实现动画效果
- Android中的XML解析-DOM的使用与开发技巧
- [Android开发]Android之使用Http协议实现文件上传功能
- Android开发:使用序列化接口Parcelable、Serializable实现Activity间传递复杂数据类型参数
- Android开发(10)使用SQLiteDatabase操作SQLite数据库实现增删改查(源码)
- android开发(24)使用SQLiteOpenHelper的onUpgrade实现数据库版本升级
- 如何搭建Android的开发环境->在unbuntu 10.04 上使用ubuntu的一些技巧(四)
- 【Android UI设计与开发】第02期:引导界面(二)使用ViewPager实现欢迎引导页面
- android开发基础:Intent与Bundle的使用,实现页面跳转及信息传递