仿微信6.0主界面实现

来源:互联网 发布:天狼星期货软件管网 编辑:程序博客网 时间:2024/06/11 22:07

终于实现完QQ6.0的主界面。学习到的知识点也较多,也注意到自己很多要学习的。


参考资料:

http://www.imooc.com/learn/273 视频学习

http://byandby.iteye.com/blog/825330 android Canvas类介绍
http://www.cnblogs.com/feisky/archive/2010/01/10/1643460.html   Android Bitmap和Canvas学习笔记
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android Canvas绘图详解(图文)
http://trylovecatch.iteye.com/blog/1189452    android 画图之setXfermode 
http://blog.csdn.net/stevenhu_223/article/details/9705173 解决android4.0系统中菜单(Menu)添加Icon无效问题


*总的思路是,自定义控件,提供一个公共的接口实现图标和文字的渐变实现,而这通过设置透明度值即可。不同形状的图标充满颜色,

运用到是 Paint#setXfermode(new PorterDuffXfermode(Mode mode)) 这种多样的图片处理。外部通过ViewPager的监听得到滚动方向

和距离的数据,通过公共方法设置alpha值即可实现。


*首先完成ActionBar的实现

主要是运用反射使 ①系统显示浮动菜单提示 ②菜单带图标显示。

(a)使溢出浮动菜单的三个竖点换成自己的图标,在 style.xml中定义

    <!-- Application theme. -->    <style name="AppTheme" parent="AppBaseTheme">        <!-- All customizations that are NOT specific to a particular API-level can go here. -->        <item name="android:actionOverflowButtonStyle">@style/ActionBarOverflowIconStyle</item>    </style>    <style name="ActionBarOverflowIconStyle">        <item name="android:src">@drawable/actionbar_add_icon</item>    </style>

(b)设置ActionBar显示溢出菜单

/** * 设置显示溢出更多菜单 运用反射,更改 ViewConfiguration中一个字段的值 */private void setOverflow() {//ViewConfiguration//Contains methods to standard constants used in the UI //for timeouts, sizes, and distances.ViewConfiguration viewConfig = ViewConfiguration.get(this);try {Field field = viewConfig.getClass().getDeclaredField("sHasPermanentMenuKey");field.setAccessible(true); // Setting this flag to false will enable// access checks, setting to true will// disable them.field.setBoolean(viewConfig, false);} catch (NoSuchFieldException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();}}

(c)设置菜单带图标

①下面两个得到方法对象的区别

Class#getMethod() --> 

Returns a Method object which represents the public method with the specified name and parameter types.

Class#getDeclaredMethod()-->

Returns a Method object which represents the method matching the specified name and parameter types that is declared by the class represented by this Class.

/** * 设置菜单选项显示图标 MenuBuild方法setOptionalIconsVisible传入true参数 运用反射实现 */private void initMenuIcon(Menu menu) {// Class c = MenuBuild.class;try {Class c = menu.getClass();//Method m1 = c.getMethod("setOptionalIconsVisible", Boolean.class);Method m = c.getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);m.setAccessible(true);m.invoke(menu, true);} catch (NoSuchMethodException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();}}

(d)再监听菜单点击

public boolean onOptionsItemSelected(MenuItem item) ;

(e)这样,ActionBar就完成了


*完成自定义控件

完成自定义控件时,遇到好一些问题。首先记录说明这几点

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
这个函数是完成一些测量边距、控件大小等

会奇怪的是:

Bitmap m = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),Config.ARGB_8888);

当 创建位图是,尝试在里边获取 getMeasuredWidth() 和 getMeasuredHeight() 时,(xml)会提示错误,好像是大小必须大于0,只好把它

放到 onDraw()中去执行

当写好继承自 View 的自定义控件是,发现不能绘画出来,onDraw()根本没有调用。调了半天,然后经过比对,和demo实验,发现原因:layout_width 或 layout_height 

为 0 时,onDraw()不会调用,invalidate()无效。

Canvas#drawText()时,文字的位置取决于Paint#setTextAlign()

当参数设为:Paint.Align.CENTER

它指的是底边正中心。例如,设为 (100, 100),则 Hello.World 中的中间的小点就为 (100, 100)

④Paint#setXfermode(),找资料时,发现都展示一幅示意图,纳闷这是哪里来的,文档中没有。后来发现,这是在 示例代码的 APIDemo,这也是

要学习的。

实例:

Bitmap dst = Bitmap.createBitmap(400, 400, Config.ARGB_8888);Canvas c1 = new Canvas(dst);Paint p1 = new Paint();p1.setColor(Color.BLUE);c1.drawOval(new RectF(0, 0, 300, 300), p1);Bitmap src = Bitmap.createBitmap(400, 400, Config.ARGB_8888);Canvas c2 = new Canvas(src);Paint p2 = new Paint();p2.setColor(Color.YELLOW);c2.drawRect(150, 150, 400, 400, p2);Paint paint = new Paint();canvas.translate(10, 10);canvas.drawColor(Color.WHITE);canvas.drawBitmap(dst, 0, 0, null);// paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));canvas.drawBitmap(src, 0, 0, paint);canvas.translate(10, 400);Bitmap bitmap = Bitmap.createBitmap(400, 400, Config.ARGB_8888);paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));Canvas c3 = new Canvas(bitmap);c3.drawBitmap(dst, 0, 0, null);paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));c3.drawBitmap(src, 0, 0, paint);canvas.drawBitmap(bitmap, 0, 0, null);

很奇怪,颜色没有渐变。原来顺序错误,没有意识到 setColor()时,也设置了Alpha  (ARGB)

(a)

代码:

/** * 自定义控件 1、获取属性 2、得到相关高度 3、绘画 *  * @author Administrator *  */public class BottomItemView1 extends View {private static final String TAG = "BottomItemView1";// 相关属性private Bitmap iconBitmap;private int color;private int textSize;private String textString;/** * 图片大小 */private int iconWidth;private Rect iconRect;private Rect textBoundRect;private Paint textPaint;private int textCenterX;private int textCenterY;/** * 透明度 0x00-->0xFF,完全透明到完全不透明 */private int alpha = 0x00;public void setAlphaAndReDraw(int alpha) {this.alpha = alpha % 256;if (Looper.getMainLooper() == Looper.myLooper()) {invalidate();} else {postInvalidate();}}public BottomItemView1(Context context) {this(context, null);// TODO Auto-generated constructor stub}public BottomItemView1(Context context, AttributeSet attrs) {this(context, attrs, 0);// TODO Auto-generated constructor stub}public BottomItemView1(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);Log.e(TAG,"BottomItemView1(Context context, AttributeSet attrs, int defStyle);");initAttrs(context, attrs);initRes();}private void initRes() {textBoundRect = new Rect();textPaint = new Paint();textPaint.setColor(color);textPaint.setTextSize(textSize);textPaint.setTextAlign(Paint.Align.CENTER);iconRect = new Rect();}/** * 获取相关属性 */private void initAttrs(Context context, AttributeSet set) {TypedArray ta = context.obtainStyledAttributes(set,R.styleable.BottomView);iconBitmap = ((BitmapDrawable) ta.getDrawable(R.styleable.BottomView_icon)).getBitmap();color = ta.getColor(R.styleable.BottomView_color,Color.parseColor("#ff76B34D"));textSize = (int) ta.getDimension(R.styleable.BottomView_text_size,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12,context.getResources().getDisplayMetrics()));textString = ta.getString(R.styleable.BottomView_text);ta.recycle();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// TODO Auto-generated method stubsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);Log.e(TAG, "onMeasure()");modifyRes();}private void modifyRes() {textPaint.getTextBounds(textString, 0, textString.length(),textBoundRect);int minWidth = getMeasuredWidth() - getPaddingLeft()- getPaddingRight();int minHeight = getMeasuredHeight() - getPaddingBottom()- getPaddingTop() - textBoundRect.height();iconWidth = Math.min(minWidth, minHeight);int iconStartX = getMeasuredWidth() / 2 - iconWidth / 2+ (getPaddingLeft() - getPaddingRight());int iconStartY = getPaddingTop();iconRect.set(iconStartX, iconStartY, iconStartX + iconWidth, iconStartY+ iconWidth);textCenterX = getMeasuredWidth() / 2;textCenterY = iconWidth + textBoundRect.height();}@Overrideprotected void onDraw(Canvas canvas) {// TODO Auto-generated method stubsuper.onDraw(canvas);Log.e(TAG, "onDraw()");initCanvas(canvas, alpha);}private void initCanvas(Canvas canvas, int alpha) {Bitmap m = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),Config.ARGB_8888);Canvas c = new Canvas(m);Paint p = new Paint();p.setColor(color);p.setAlpha(alpha);c.drawRect(iconRect, p);p.setXfermode(new PorterDuffXfermode(Mode.DST_IN));c.drawBitmap(iconBitmap, null, iconRect, p);canvas.drawBitmap(iconBitmap, null, iconRect, null);canvas.drawBitmap(m, 0, 0, null);// 绘制原文本textPaint.setColor(Color.GRAY);canvas.drawText(textString, textCenterX, textCenterY, textPaint);// 绘制变色文本/* * Set the paint's color. Note that the color is an int containing alpha * as well as r,g,b. This 32bit value is not premultiplied, meaning that * its alpha can be any value, regardless of the values of r,g,b. See * the Color class for more details. */textPaint.setColor(color);textPaint.setAlpha(alpha);canvas.drawText(textString, textCenterX, textCenterY, textPaint);}}



*产生颜色渐变效果

设置ViewPager的回调监听函数,在 

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) 

方法中,找到 position 的规律,然后设置透明度alpha值

@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {Log.e(TAG, "-----------onPageScrolled()----------");Log.e(TAG, "postion-->"+position);Log.e(TAG, "positionOffset-->"+positionOffset);Log.e(TAG, "positionOffsetPixels-->"+positionOffsetPixels);tabEffect(position, positionOffset, positionOffsetPixels);}/** * 自定义控件颜色渐变 * @param position * @param positionOffset * @param positionOffsetPixels */private void tabEffect(int position, float positionOffset, int positionOffsetPixels) {if (position == 0) {leftTab = tab1;rightTab = tab2;} else if (position == 1) {leftTab = tab2;rightTab = tab3;} else if (position == 2) {leftTab = tab3;rightTab = tab4;} else if (position == 3 ) {leftTab = tab4;rightTab = tab4;}int alpha = (int) (positionOffset * 0xFF);rightTab.setAlphaAndReDraw(alpha);leftTab.setAlphaAndReDraw(0xFf-alpha);}


*其中遇到的 “refresh external folder”的进程提示,总是显示在 99%,编译极为不方便。解决的方法是,取消源代码的关联


*源码:http://download.csdn.net/detail/learn2012/8467565


0 0
原创粉丝点击