效果图

原理介绍

1、先绘制一个颜色(例如:粉红)

2、设置Mode=DST_IN

3、绘制我们这个可爱的小机器人

回答我,显示什么,是不是显示交集,交集是什么?交集是我们的小机器人的非透明区域,也就是那张脸,除了两个眼;

好了,那怎么变色呢?

我绘制一个颜色的时候,难道不能设置alpha么

自定义图标控件

自定义属性

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <attr name="icon" format="reference" />
  4. <attr name="color" format="color" />
  5. <attr name="text" format="string" />
  6. <attr name="text_size" format="dimension" />
  7. <declare-styleable name="ChangeColorIconView">
  8. <attr name="icon" />
  9. <attr name="color" />
  10. <attr name="text" />
  11. <attr name="text_size" />
  12. </declare-styleable>
  13. </resources>

绘制图标

绘制图标有很多步骤呀,我来列一列

1、计算alpha(默认为0)

2、绘制原图

3、在绘图区域,绘制一个纯色块(设置了alpha),此步绘制在内存的bitmap上

4、设置mode,针对内存中的bitmap上的paint

5、绘制我们的图标,此步绘制在内存的bitmap上

6、绘制原文本

7、绘制设置alpha和颜色后的文本

8、将内存中的bitmap绘制出来

根据上面的步骤,可以看出来,我们的图标其实绘制了两次,为什么要绘制原图呢,因为我觉得比较好看。

3-5步骤,就是我们上面分析的原理

6-7步,是绘制文本,可以看到,我们的文本就是通过设置alpha实现的

  1. package com.zhy.weixin6.ui;
  2. import android.content.Context;
  3. import android.content.res.TypedArray;
  4. import android.graphics.Bitmap;
  5. import android.graphics.Bitmap.Config;
  6. import android.graphics.BitmapFactory;
  7. import android.graphics.Canvas;
  8. import android.graphics.Paint;
  9. import android.graphics.PorterDuff;
  10. import android.graphics.PorterDuffXfermode;
  11. import android.graphics.Rect;
  12. import android.graphics.drawable.BitmapDrawable;
  13. import android.os.Bundle;
  14. import android.os.Looper;
  15. import android.os.Parcelable;
  16. import android.util.AttributeSet;
  17. import android.util.Log;
  18. import android.util.TypedValue;
  19. import android.view.View;
  20. public class ChangeColorIconWithTextView extends View
  21. {
  22. private Bitmap mBitmap;
  23. private Canvas mCanvas;
  24. private Paint mPaint;
  25. /**
  26. * 颜色
  27. */
  28. private int mColor = 0xFF45C01A;
  29. /**
  30. * 透明度 0.0-1.0
  31. */
  32. private float mAlpha = 0f;
  33. /**
  34. * 图标
  35. */
  36. private Bitmap mIconBitmap;
  37. /**
  38. * 限制绘制icon的范围
  39. */
  40. private Rect mIconRect;
  41. /**
  42. * icon底部文本
  43. */
  44. private String mText = "微信";
  45. private int mTextSize = (int) TypedValue.applyDimension(
  46. TypedValue.COMPLEX_UNIT_SP, 10, getResources().getDisplayMetrics());
  47. private Paint mTextPaint;
  48. private Rect mTextBound = new Rect();
  49. public ChangeColorIconWithTextView(Context context)
  50. {
  51. super(context);
  52. }
  53. /**
  54. * 初始化自定义属性值
  55. *
  56. * @param context
  57. * @param attrs
  58. */
  59. public ChangeColorIconWithTextView(Context context, AttributeSet attrs)
  60. {
  61. super(context, attrs);
  62. // 获取设置的图标
  63. TypedArray a = context.obtainStyledAttributes(attrs,
  64. R.styleable.ChangeColorIconView);
  65. int n = a.getIndexCount();
  66. for (int i = 0; i < n; i++)
  67. {
  68. int attr = a.getIndex(i);
  69. switch (attr)
  70. {
  71. case R.styleable.ChangeColorIconView_icon:
  72. BitmapDrawable drawable = (BitmapDrawable) a.getDrawable(attr);
  73. mIconBitmap = drawable.getBitmap();
  74. break;
  75. case R.styleable.ChangeColorIconView_color:
  76. mColor = a.getColor(attr, 0x45C01A);
  77. break;
  78. case R.styleable.ChangeColorIconView_text:
  79. mText = a.getString(attr);
  80. break;
  81. case R.styleable.ChangeColorIconView_text_size:
  82. mTextSize = (int) a.getDimension(attr, TypedValue
  83. .applyDimension(TypedValue.COMPLEX_UNIT_SP, 10,
  84. getResources().getDisplayMetrics()));
  85. break;
  86. }
  87. }
  88. a.recycle();
  89. mTextPaint = new Paint();
  90. mTextPaint.setTextSize(mTextSize);
  91. mTextPaint.setColor(0xff555555);
  92. // 得到text绘制范围
  93. mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
  94. }
  95. @Override
  96. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
  97. {
  98. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  99. // 得到绘制icon的宽
  100. int bitmapWidth = Math.min(getMeasuredWidth() - getPaddingLeft()
  101. - getPaddingRight(), getMeasuredHeight() - getPaddingTop()
  102. - getPaddingBottom() - mTextBound.height());
  103. int left = getMeasuredWidth() / 2 - bitmapWidth / 2;
  104. int top = (getMeasuredHeight() - mTextBound.height()) / 2 - bitmapWidth
  105. / 2;
  106. // 设置icon的绘制范围
  107. mIconRect = new Rect(left, top, left + bitmapWidth, top + bitmapWidth);
  108. }
  109. @Override
  110. protected void onDraw(Canvas canvas)
  111. {
  112. int alpha = (int) Math.ceil((255 * mAlpha));
  113. canvas.drawBitmap(mIconBitmap, null, mIconRect, null);
  114. setupTargetBitmap(alpha);
  115. drawSourceText(canvas, alpha);
  116. drawTargetText(canvas, alpha);
  117. canvas.drawBitmap(mBitmap, 0, 0, null);
  118. }
  119. private void setupTargetBitmap(int alpha)
  120. {
  121. mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
  122. Config.ARGB_8888);
  123. mCanvas = new Canvas(mBitmap);
  124. mPaint = new Paint();
  125. mPaint.setColor(mColor);
  126. mPaint.setAntiAlias(true);
  127. mPaint.setDither(true);
  128. mPaint.setAlpha(alpha);
  129. mCanvas.drawRect(mIconRect, mPaint);
  130. mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
  131. mPaint.setAlpha(255);
  132. mCanvas.drawBitmap(mIconBitmap, null, mIconRect, mPaint);
  133. }
  134. private void drawSourceText(Canvas canvas, int alpha)
  135. {
  136. mTextPaint.setTextSize(mTextSize);
  137. mTextPaint.setColor(0xff333333);
  138. mTextPaint.setAlpha(255 - alpha);
  139. canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2
  140. - mTextBound.width() / 2,
  141. mIconRect.bottom + mTextBound.height(), mTextPaint);
  142. }
  143. private void drawTargetText(Canvas canvas, int alpha)
  144. {
  145. mTextPaint.setColor(mColor);
  146. mTextPaint.setAlpha(alpha);
  147. canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2
  148. - mTextBound.width() / 2,
  149. mIconRect.bottom + mTextBound.height(), mTextPaint);
  150. }
  151. public void setIconAlpha(float alpha)
  152. {
  153. this.mAlpha = alpha;
  154. invalidateView();
  155. }
  156. private void invalidateView()
  157. {
  158. if (Looper.getMainLooper() == Looper.myLooper())
  159. {
  160. invalidate();
  161. } else
  162. {
  163. postInvalidate();
  164. }
  165. }
  166. public void setIconColor(int color)
  167. {
  168. mColor = color;
  169. }
  170. public void setIcon(int resId)
  171. {
  172. this.mIconBitmap = BitmapFactory.decodeResource(getResources(), resId);
  173. if (mIconRect != null)
  174. invalidateView();
  175. }
  176. public void setIcon(Bitmap iconBitmap)
  177. {
  178. this.mIconBitmap = iconBitmap;
  179. if (mIconRect != null)
  180. invalidateView();
  181. }
  182. private static final String INSTANCE_STATE = "instance_state";
  183. private static final String STATE_ALPHA = "state_alpha";
  184. @Override
  185. protected Parcelable onSaveInstanceState()
  186. {
  187. Bundle bundle = new Bundle();
  188. bundle.putParcelable(INSTANCE_STATE, super.onSaveInstanceState());
  189. bundle.putFloat(STATE_ALPHA, mAlpha);
  190. return bundle;
  191. }
  192. @Override
  193. protected void onRestoreInstanceState(Parcelable state)
  194. {
  195. if (state instanceof Bundle)
  196. {
  197. Bundle bundle = (Bundle) state;
  198. mAlpha = bundle.getFloat(STATE_ALPHA);
  199. super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE));
  200. } else
  201. {
  202. super.onRestoreInstanceState(state);
  203. }
  204. }
  205. }

MainActivity

  1. package com.zhy.weixin6.ui;
  2. import java.lang.reflect.Field;
  3. import java.lang.reflect.Method;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. import android.annotation.SuppressLint;
  7. import android.os.Bundle;
  8. import android.support.v4.app.Fragment;
  9. import android.support.v4.app.FragmentActivity;
  10. import android.support.v4.app.FragmentPagerAdapter;
  11. import android.support.v4.view.ViewPager;
  12. import android.support.v4.view.ViewPager.OnPageChangeListener;
  13. import android.view.Menu;
  14. import android.view.MenuItem;
  15. import android.view.View;
  16. import android.view.View.OnClickListener;
  17. import android.view.ViewConfiguration;
  18. import android.view.Window;
  19. import android.widget.SearchView;
  20. import android.widget.Toast;
  21. @SuppressLint("NewApi")
  22. public class MainActivity extends FragmentActivity implements
  23. OnPageChangeListener, OnClickListener
  24. {
  25. private ViewPager mViewPager;
  26. private List<Fragment> mTabs = new ArrayList<Fragment>();
  27. private FragmentPagerAdapter mAdapter;
  28. private String[] mTitles = new String[] { "First Fragment!",
  29. "Second Fragment!", "Third Fragment!", "Fourth Fragment!" };
  30. private List<ChangeColorIconWithTextView> mTabIndicator = new ArrayList<ChangeColorIconWithTextView>();
  31. @Override
  32. protected void onCreate(Bundle savedInstanceState)
  33. {
  34. super.onCreate(savedInstanceState);
  35. setContentView(R.layout.activity_main);
  36. setOverflowShowingAlways();
  37. getActionBar().setDisplayShowHomeEnabled(false);
  38. mViewPager = (ViewPager) findViewById(R.id.id_viewpager);
  39. initDatas();
  40. mViewPager.setAdapter(mAdapter);
  41. mViewPager.setOnPageChangeListener(this);
  42. }
  43. private void initDatas()
  44. {
  45. for (String title : mTitles)
  46. {
  47. TabFragment tabFragment = new TabFragment();
  48. Bundle args = new Bundle();
  49. args.putString("title", title);
  50. tabFragment.setArguments(args);
  51. mTabs.add(tabFragment);
  52. }
  53. mAdapter = new FragmentPagerAdapter(getSupportFragmentManager())
  54. {
  55. @Override
  56. public int getCount()
  57. {
  58. return mTabs.size();
  59. }
  60. @Override
  61. public Fragment getItem(int arg0)
  62. {
  63. return mTabs.get(arg0);
  64. }
  65. };
  66. initTabIndicator();
  67. }
  68. SearchView searchView;
  69. @Override
  70. public boolean onCreateOptionsMenu(Menu menu)
  71. {
  72. getMenuInflater().inflate(R.menu.main, menu);
  73. MenuItem searchItem = menu.findItem(R.id.action_search);
  74. searchView = (SearchView) searchItem.getActionView();
  75. return true;
  76. }
  77. @Override
  78. public boolean onSearchRequested() {
  79. // TODO Auto-generated method stub
  80. Toast.makeText(getApplicationContext(), searchView.getQuery(), 0).show();
  81. return super.onSearchRequested();
  82. }
  83. private void initTabIndicator()
  84. {
  85. ChangeColorIconWithTextView one = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_one);
  86. ChangeColorIconWithTextView two = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_two);
  87. ChangeColorIconWithTextView three = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_three);
  88. ChangeColorIconWithTextView four = (ChangeColorIconWithTextView) findViewById(R.id.id_indicator_four);
  89. mTabIndicator.add(one);
  90. mTabIndicator.add(two);
  91. mTabIndicator.add(three);
  92. mTabIndicator.add(four);
  93. one.setOnClickListener(this);
  94. two.setOnClickListener(this);
  95. three.setOnClickListener(this);
  96. four.setOnClickListener(this);
  97. one.setIconAlpha(1.0f);
  98. }
  99. @Override
  100. public void onPageSelected(int arg0)
  101. {
  102. }
  103. @Override
  104. public void onPageScrolled(int position, float positionOffset,
  105. int positionOffsetPixels)
  106. {
  107. // Log.e("TAG", "position = " + position + " , positionOffset = "
  108. // + positionOffset);
  109. if (positionOffset > 0)
  110. {
  111. ChangeColorIconWithTextView left = mTabIndicator.get(position);
  112. ChangeColorIconWithTextView right = mTabIndicator.get(position + 1);
  113. left.setIconAlpha(1 - positionOffset);
  114. right.setIconAlpha(positionOffset);
  115. }
  116. }
  117. @Override
  118. public void onPageScrollStateChanged(int state)
  119. {
  120. }
  121. @Override
  122. public void onClick(View v)
  123. {
  124. resetOtherTabs();
  125. switch (v.getId())
  126. {
  127. case R.id.id_indicator_one:
  128. mTabIndicator.get(0).setIconAlpha(1.0f);
  129. mViewPager.setCurrentItem(0, false);
  130. break;
  131. case R.id.id_indicator_two:
  132. mTabIndicator.get(1).setIconAlpha(1.0f);
  133. mViewPager.setCurrentItem(1, false);
  134. break;
  135. case R.id.id_indicator_three:
  136. mTabIndicator.get(2).setIconAlpha(1.0f);
  137. mViewPager.setCurrentItem(2, false);
  138. break;
  139. case R.id.id_indicator_four:
  140. mTabIndicator.get(3).setIconAlpha(1.0f);
  141. mViewPager.setCurrentItem(3, false);
  142. break;
  143. }
  144. }
  145. /**
  146. * 重置其他的Tab
  147. */
  148. private void resetOtherTabs()
  149. {
  150. for (int i = 0; i < mTabIndicator.size(); i++)
  151. {
  152. mTabIndicator.get(i).setIconAlpha(0);
  153. }
  154. }
  155. @Override
  156. public boolean onMenuOpened(int featureId, Menu menu)
  157. {
  158. if (featureId == Window.FEATURE_ACTION_BAR && menu != null)
  159. {
  160. if (menu.getClass().getSimpleName().equals("MenuBuilder"))
  161. {
  162. try
  163. {
  164. Method m = menu.getClass().getDeclaredMethod(
  165. "setOptionalIconsVisible", Boolean.TYPE);
  166. m.setAccessible(true);
  167. m.invoke(menu, true);
  168. } catch (Exception e)
  169. {
  170. }
  171. }
  172. }
  173. return super.onMenuOpened(featureId, menu);
  174. }
  175. private void setOverflowShowingAlways()
  176. {
  177. try
  178. {
  179. // true if a permanent menu key is present, false otherwise.
  180. ViewConfiguration config = ViewConfiguration.get(this);
  181. Field menuKeyField = ViewConfiguration.class
  182. .getDeclaredField("sHasPermanentMenuKey");
  183. menuKeyField.setAccessible(true);
  184. menuKeyField.setBoolean(config, false);
  185. } catch (Exception e)
  186. {
  187. e.printStackTrace();
  188. }
  189. }
  190. }

Activity里面代码虽然没什么注释,但是很简单哈,就是初始化Fragment,得到我们的适配器,然后设置给ViewPager;

initTabIndicator我们初始化我们的自定义控件,以及加上了点击事件;

唯一一个需要指出的就是:

我们在onPageScrolled中,动态的获取position以及positionOffset,然后拿到左右两个View,设置positionOffset ;

两个反射的方法,是控制Actionbar的图标的,和点击menu按键显示的

TabFragment

  1. package com.zhy.weixin6.ui;
  2. import android.graphics.Color;
  3. import android.os.Bundle;
  4. import android.support.v4.app.Fragment;
  5. import android.view.Gravity;
  6. import android.view.LayoutInflater;
  7. import android.view.View;
  8. import android.view.ViewGroup;
  9. import android.widget.TextView;
  10. public class TabFragment extends Fragment
  11. {
  12. private String mTitle = "Default";
  13. public TabFragment()
  14. {
  15. }
  16. @Override
  17. public View onCreateView(LayoutInflater inflater, ViewGroup container,
  18. Bundle savedInstanceState)
  19. {
  20. if (getArguments() != null)
  21. {
  22. mTitle = getArguments().getString("title");
  23. }
  24. TextView textView = new TextView(getActivity());
  25. textView.setTextSize(20);
  26. textView.setBackgroundColor(Color.parseColor("#ffffffff"));
  27. textView.setGravity(Gravity.CENTER);
  28. textView.setText(mTitle);
  29. return textView;
  30. }
  31. }

menu.xml文件

  1. <menu xmlns:android="http://schemas.android.com/apk/res/android" >
  2. <item
  3. android:id="@+id/action_search"
  4. android:actionViewClass="android.widget.SearchView"
  5. android:icon="@drawable/actionbar_search_icon"
  6. android:showAsAction="ifRoom|collapseActionView"
  7. android:title="@string/action_search"/>
  8. <item
  9. android:id="@+id/action_group_chat"
  10. android:icon="@drawable/ofm_group_chat_icon"
  11. android:title="@string/action_group_chat"/>
  12. <item
  13. android:id="@+id/action_add_friend"
  14. android:icon="@drawable/ofm_add_icon"
  15. android:title="@string/action_add_friend"/>
  16. <item
  17. android:id="@+id/action_scan"
  18. android:icon="@drawable/ofm_qrcode_icon"
  19. android:title="@string/action_scan"/>
  20. <item
  21. android:id="@+id/action_feed"
  22. android:icon="@drawable/ofm_feedback_icon"
  23. android:title="@string/action_feed"/>
  24. </menu>

源码下载

源码下载

参考链接

Android 高仿微信6.0主界面 带你玩转切换图标变色 - Hongyang - 博客频道 - CSDN.NET

http://blog.csdn.net/lmj623565791/article/details/41087219

Android仿微信界面的更多相关文章

  1. Android仿微信界面--使用Fragment实现(慕课网笔记)

    1 效果图  这里我们没有实现滑动切换view的功能 2 具体实现: 2.1 布局文件:top.xml, bottom.xml,tab01.xml,tab02.xml,tab03.xml,tab04. ...

  2. Android ActionBar仿微信界面

    ActionBar仿微信界面 1.学习了别人的两篇关于ActionBar博客,在结合别人的文章来仿造一下微信的界面: 思路如下:1).利用ActionBar生成界面的头部,在用ActionBar的Ac ...

  3. Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等

    仿照微信,朋友圈分享图片功能 .可以进行图片的多张选择,拍照添加图片,以及进行图片的预览,预览时可以进行缩放,并且可以删除选中状态的图片 .很不错的源码,大家有需要可以下载看看 . 微信 微信 微信 ...

  4. Android 仿微信小视频录制

    Android 仿微信小视频录制 WechatShortVideo和WechatShortVideo文章

  5. H5仿微信界面教程(一)

    前言 先来张图,仿微信界面,界面如下,并不完全一模一样,只能说有些类似,希望大家见谅. 1 用到的知识点 jQuery WeUI 是WeUI的一个jQuery实现版本,除了实现了官方插件之外,它还提供 ...

  6. h5移动端聊天室|仿微信界面聊天室|h5多人聊天室

    今年的FIFA世界杯甚是精彩,最近兴致高涨就利用HTML5开发了一个手机端仿微信界面聊天室,该h5聊天室采用750px全新伸缩flex布局,以及使用rem响应式配合fontsize.js,页面弹窗则是 ...

  7. react聊天室|react+redux仿微信聊天IM实例|react仿微信界面

    一.项目概况 基于react+react-dom+react-router-dom+redux+react-redux+webpack2.0+react-photoswipe+swiper等技术混合开 ...

  8. Android控件-Fragment+ViewPager(高仿微信界面)

    什么是Fragment? Fragment是Android3.0后新增的概念,Fragment名为碎片,不过却和Activity十分相似,具有自己的生命周期,它是用来描述一些行为或一部分用户界面在一个 ...

  9. Android笔记(六十九) 仿微信界面(一)

          综合之前的Fragment和自定义组件的知识,实现微信界面 MainActivity.java package cn.lixyz.test; import android.app.Acti ...

随机推荐

  1. jQuery根据下拉列表的选择进行不同的操作

    需求:选择了某个下拉列表选项,进行不同的操作 代码部分: <!doctype html> <html> <head> <meta charset=" ...

  2. Ubuntu学习总结-03 安装软件 & 技巧

    1 UBuntu 安装 Googole Chrome 首先下载软件 wget https://dl.google.com/linux/direct/google-chrome-stable_curre ...

  3. IOC 构造函数注入vs属性注入

    1.不管是构造函数注入还是属性注入,都要先把对象给new 出来,构造函数应该也是public.2.一般使用 配置文件,属性注入,不用使用特性,直接配置,初始化或依赖,凡是注入的,都要有访问权限,pub ...

  4. object-c 的ARC 问答/介绍

    原文:http://blog.csdn.net/kmyhy/article/details/8895606 概念" Clangstatic analyzer "是一个非常有用的查找 ...

  5. Entity Framework 关系约束配置

    前言 简单的说一下自己的理解,大家应该都很明白ADO.NET,也就是原生态的数据库操作,直接通过拼接SQL语句,表与表之间通过链接(inner join  left join  或者子查询),也就是在 ...

  6. 马化腾:办公用QQ休闲用微信[Dream Catchers论坛]

    近日,香港大学举办以创新创业为主题的Dream Catchers论坛.其中腾讯董事局主席马化腾在下午两点四十五分在李兆基会议中心做了专题演讲,分享了自己的创业经历并回答了媒体人张力奋有关产品.整整对手 ...

  7. 给WordPress Page页面添加摘要输入框

    默认情况下 WordPress Page 编辑页面没有摘要(Excerpt)输入框,所以对 WordPress 进行 SEO 的时候比较麻烦. 这个时候我们就可以通过以下代码给我 WordPress ...

  8. LoadRunner中响应时间与事物时间详解

    1. 响应时间 事务是指用户在客户端做一种或多种业务所需要的操作集,通过事务函数可以标记完成该业务所需要的操作内容:另一方面事务可以用来统计用户操作的响应时间,事务响应时间是通过记录用户请求的开始时间 ...

  9. 文字编辑器kindeditor-min.js的使用

    例子: <link rel="stylesheet" type="text/css" href="<?=$WebSiteRootDir?& ...

  10. sql分页查询语句

    有关分页 SQL 的资料很多,有的使用存储过程,有的使用游标.本人不喜欢使用游标,我觉得它耗资.效率低:使用存储过程是个不错的选择,因为存储过程是经过预编译的,执行效率高,也更灵活.先看看单条 SQL ...