模仿微信的界面实现

    看了一位大神的博客,发现他有模仿微信界面实现,我决定向大神看齐!继续努力。

因为我不会制作动画,所以只能图片加说明了:

1,标题栏下面是是一个ViewPager,适配器里面的item是一个个Fragment,这个比较简单

2,ViewPager下面是一排自定义的按钮控件(继承View),随着ViewPager的滑动,字体的透明度会有一个渐变的效果,就像微信界面一样!

    

我们先自定义控件ColorChange_Iv_Tv,继承View

1,自定属性:前面的四条属性使我们需要的,后面的两条属性是,微信截取图片功能的实现,因为都是仿微信所以写到了一起

好的,我们需要的属性分别是:图标:icon;颜色:color;文本内容:text;文本的大小:text_size

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="icon" format="reference"></attr>
    <attr name="color" format="color"></attr>
    <attr name="text" format="string"></attr>
    <attr name="text_size" format="dimension"></attr>
    
    <declare-styleable name="ColorChange_Iv_Tv">
        <attr name="icon"></attr>
        <attr name="color"></attr>
        <attr name="text"></attr>
        <attr name="text_size"></attr>
    </declare-styleable>
    
    <attr name="horizontal_padding" format="dimension"></attr>
    
    <declare-styleable name="ClipImageLayout">
        <attr name="icon"></attr>
        <attr name="horizontal_padding"></attr>
    </declare-styleable>
    
</resources>

2,自定义属性后自然要拿到我们自定义属性的值:

private Bitmap iconBitmap;// 小图标对象
	private String text;// 文本对象
	private float text_size;// 文本大小
	private int color;// 选中后的颜色

	private float iconAlpha = 0f;// 透明度,越小越透明

	private Paint mPaint;//画笔对象

	private Canvas iconCanvas;//绘制icon的画布对象

	private Rect textBound;// 文本的范围
	private Rect iconBound;// 图标的范围

	public ColorChange_Iv_Tv(Context context) {
		this(context, null, 0);
	}

	public ColorChange_Iv_Tv(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public ColorChange_Iv_Tv(Context context, AttributeSet attrs,
			int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		TypedArray typeArray = context.obtainStyledAttributes(attrs,
				R.styleable.ColorChange_Iv_Tv);
		int n = typeArray.getIndexCount();
		for (int i = 0; i < n; i++) {
			int attr = typeArray.getIndex(i);
			switch (attr) {
			case R.styleable.ColorChange_Iv_Tv_color:
				color = typeArray.getColor(R.styleable.ColorChange_Iv_Tv_color,
						Color.BLUE);
				break;
			case R.styleable.ColorChange_Iv_Tv_icon:
				BitmapDrawable iconDraw = (BitmapDrawable) typeArray
						.getDrawable(R.styleable.ColorChange_Iv_Tv_icon);
				iconBitmap=iconDraw.getBitmap();
				break;
			case R.styleable.ColorChange_Iv_Tv_text:
				text = typeArray.getString(R.styleable.ColorChange_Iv_Tv_text);
				break;
			case R.styleable.ColorChange_Iv_Tv_text_size:
				text_size = typeArray.getDimension(
						R.styleable.ColorChange_Iv_Tv_text_size, TypedValue
								.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10,
										getResources().getDisplayMetrics()));
				break;
			}
		}

		typeArray.recycle();

		mPaint=new Paint();
		mPaint.setTextSize(text_size);
		mPaint.setColor(Color.BLACK);
		mPaint.setAlpha(255);
		textBound=new Rect();
		mPaint.getTextBounds(text, 0, text.length(), textBound);
	}

我们可以看到,在构造方法中我们完成了,自定义属性的获取,并且还初始化了画笔对象mPaint, 同时也获得了文本对象的范围!

包含在textBound矩阵中!

3,重写onMeasure方法,实现对布局的调整!

@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int width=getMeasuredWidth();
		int height=getMeasuredHeight();
		int iconWith=Math.min(width-getPaddingLeft()-getPaddingRight(), 
				height-textBound.height()-getPaddingTop()-getPaddingBottom());
		int left=width/2-iconWith/2;
		int top=height/2-(iconWith+textBound.height())/2;
		
		iconBound=new Rect(left, top, left+iconWith, top+iconWith);
		
	}
icon的宽度,取横纵方向剩余空间的较小值!

确定包含icon的正方形!

4,重写onDraw方法,绘图,这个是关键点:

@Override
	protected void onDraw(Canvas canvas) {
		int alpha=(int) Math.ceil(255*iconAlpha);
                //先绘制了,里层没有效果的图片
		canvas.drawBitmap(iconBitmap, null, iconBound, null);
		drawTextBlack(canvas, alpha);
                //绘制了带颜色的文本和图片
		drawText(canvas,alpha);
		drawIcon(canvas,alpha);
	}
	
	//绘制底层的文本
	private void drawTextBlack(Canvas canvas,int alpha){
		mPaint.reset();
		mPaint.setTextSize(text_size);
		mPaint.setColor(0xff333333);
		mPaint.setAlpha(255-alpha);
		canvas.drawText(text, iconBound.left+iconBound.width()/2-textBound.width()/2,
				iconBound.bottom+textBound.height(), mPaint);
	}
	
	//绘制文本
	private void drawText(Canvas canvas,int alpha){
		mPaint.reset();
		mPaint.setTextSize(text_size);
		mPaint.setColor(color);
		mPaint.setAlpha(alpha);//要先设置颜色在设置,透明度才能出效果
		//Log.i("wangsongbin", alpha+"");
		canvas.drawText(text, iconBound.left+iconBound.width()/2-textBound.width()/2,
				iconBound.bottom+textBound.height(), mPaint);
	}
	
	//绘制icon
	private void drawIcon(Canvas canvas,int alpha){
		Bitmap bitmap=Bitmap.createBitmap(iconBound.width(), 
				iconBound.height(), Config.ARGB_8888);
		Canvas iconCanvas=new Canvas(bitmap);
		
		mPaint.reset();
		mPaint.setColor(color);
		mPaint.setAntiAlias(true);
		mPaint.setDither(true);
		mPaint.setAlpha(alpha);
                //先绘制了颜色
		iconCanvas.drawRect(0,0,iconBound.width(),iconBound.height(), mPaint);
	        //再设置,Xfermode的<span style="font-family: Arial, Helvetica, sans-serif;">PorterDuff.Mode.DST_IN</span><span style="font-family: Arial, Helvetica, sans-serif;">模式,即只显示被覆盖的地方,如果有不明白,请看<a target=_blank href="http://blog.youkuaiyun.com/wangsongbin893603021/article/details/45012015">点击打开链接</a></span>
		mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
		mPaint.setAlpha(255);
		iconCanvas.drawBitmap(iconBitmap, 
				null, new RectF(0, 0, iconBound.width(), iconBound.height()), mPaint);
		
		canvas.drawBitmap(bitmap, null,iconBound, null);
		
	}
最后,给个方法接口,让用户动态设置透明度,达到渐变的效果

//设置透明度
	public void setIconAlpha(float iconAlpha){
		this.iconAlpha=iconAlpha;
		if(Looper.getMainLooper()==Looper.myLooper()){
			invalidate();
		}else{
			postInvalidate();
		}
	}
最后,没了保证,用户的界面发生横竖屏切换导致的activity重启,导致自定义控件的数据丢失,我重写了:onSaveInstanceState,和onRestoreInstanceState!

具体代码:

private final String instance_state="instance_state";
	private final String state_alpha="state_alpha";
	@Override
	protected Parcelable onSaveInstanceState() {
		Bundle bundle=new Bundle();
		bundle.putParcelable(instance_state, super.onSaveInstanceState());
		bundle.putFloat(state_alpha, iconAlpha);
		return bundle;
	}
	
	@Override
	protected void onRestoreInstanceState(Parcelable state) {
		if(state instanceof Bundle){
			Bundle bundle=(Bundle) state;
			iconAlpha=bundle.getFloat(state_alpha);
			super.onRestoreInstanceState(bundle.getParcelable(instance_state));
		}else{
			super.onRestoreInstanceState(state);
		}
	}
到此自定控件就已经完成了。现在是利用的时候了!

先看一下MainActivity的布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:wang="http://schemas.android.com/apk/res/com.wang.demo_weixin_60_ui"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.wang.demo_weixin_60_ui.MainActivity" >
    
    <android.support.v4.view.ViewPager
        android:id="@+id/vp_content"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_above="@+id/ll_tab">
    </android.support.v4.view.ViewPager>
    
    
   <LinearLayout 
       android:id="@+id/ll_tab"
       android:layout_width="fill_parent"
       android:layout_height="60dp"
       android:background="@drawable/tabbg"
       android:layout_alignParentBottom="true"
       android:orientation="horizontal">
       
        <com.wang.demo_weixin_60_ui.view.ColorChange_Iv_Tv 
           android:id="@+id/tabview_one"
           android:layout_width="0dp"
           android:layout_weight="1"
           android:layout_height="fill_parent"
           android:padding="5dp"
           wang:icon="@drawable/ic_menu_start_conversation"
           wang:color="#ff0000"
           wang:text="微信"
           wang:text_size="12sp"/>
        
        <com.wang.demo_weixin_60_ui.view.ColorChange_Iv_Tv
           android:id="@+id/tabview_two" 
           android:layout_width="0dp"
           android:layout_weight="1"
           android:layout_height="fill_parent"
           android:padding="5dp"
           wang:icon="@drawable/ic_menu_friendslist"
           wang:color="#ff0000"
           wang:text="通讯录"
           wang:text_size="12sp"/>
         
        <com.wang.demo_weixin_60_ui.view.ColorChange_Iv_Tv 
           android:id="@+id/tabview_three"
           android:layout_width="0dp"
           android:layout_weight="1"
           android:layout_height="fill_parent"
           android:padding="5dp"
           wang:icon="@drawable/ic_menu_emoticons"
           wang:color="#ff0000"
           wang:text="发现"
           wang:text_size="12sp"/>
          
      <com.wang.demo_weixin_60_ui.view.ColorChange_Iv_Tv 
           android:id="@+id/tabview_four"
           android:layout_width="0dp"
           android:layout_weight="1"
           android:layout_height="fill_parent"
           android:padding="5dp"
           wang:icon="@drawable/ic_menu_allfriends"
           wang:color="#ff0000"
           wang:text="我"
           wang:text_size="12sp"/>
       
   </LinearLayout>
   
    

</RelativeLayout>

其次是MainActivity中的利用,其中最主要的监听是:

private void registerListener() {
		vp_content.setOnPageChangeListener(new OnPageChangeListener() {
			
			@Override
			public void onPageSelected(int arg0) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void onPageScrolled(int positon, float positonOffSet, int positionOffsetPixels) {
				if(positonOffSet>0){
					ColorChange_Iv_Tv left=tabList.get(positon);
					ColorChange_Iv_Tv right=tabList.get(positon+1);
					left.setIconAlpha(1-positonOffSet);
					right.setIconAlpha(positonOffSet);
//这段代码有不明白的,可以把positionOffSet打印出来,在logcat里面比较一下
				}
				
			}
			
			@Override
			public void onPageScrollStateChanged(int arg0) {
				// TODO Auto-generated method stub
				
			}
		});
		
	}

在下面都是很简单的内容,大家直接看代码哈!

源代码下载









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值