仿微信6.0主界面实现

终于实现完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 block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.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 block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.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();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.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();

	}

	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.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值

			
			@Override
			public 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值