QQ顶栏扁圆透明背景移动的实现

QQ顶栏椭圆透明背景移动的实现!
先看ANDROID QQ截图:
QQ顶栏扁圆透明背景移动的实现
再看DEMO截图:
QQ顶栏扁圆透明背景移动的实现
QQ顶栏扁圆透明背景移动的实现

直接看代码:

public class test3 extends Activity {
	
	private NewLayOut layout;
	
	private myThread mThread;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
    	layout = (NewLayOut) inflater.inflate(R.layout.move, null);
    	
    	ImageView button = (ImageView)layout.findViewById(R.id.ImageView01);
    	button.setOnClickListener(mClickListener);
    	ImageView button2 = (ImageView)layout.findViewById(R.id.ImageView02);
    	button2.setOnClickListener(mClickListener);
    	ImageView button3 = (ImageView)layout.findViewById(R.id.ImageView03);
    	button3.setOnClickListener(mClickListener);
    	
    	this.setContentView(layout);
    }
    
    private View.OnClickListener mClickListener = new View.OnClickListener() {
		
		public void onClick(View v) {
			startMove(v);
		}
	};
	
	private void startMove(View v)
    {
    	stopThread();//停止之前的线程
		mThread = new myThread(v);
		mThread.start();
    }
	
	private void stopThread()
    {
    	if (mThread != null)
		{
    		try
			{
    			layout.mIsStop = true;
				mThread.join();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
    }
	
	class myThread extends Thread
    {
    	private View mView;
    	
    	public myThread(View v){ this.mView = v; }
    	
		public void run() {
			layout.doWork(this.mView);
		}
    	
    }
}


NewLayOut 类 继承 LinearLayout,因为需要在LinearLayout里面画图

package test3.program;

import android.content.Context;

import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;

public class NewLayOut extends LinearLayout {

	private static final short SPEED = 15;
	
	private Context mContext;
	private Rect mNowRect;//当前的区域
	private Rect mEndRect;//结束的区域
	private BitmapDrawable mSelecter;//移动的半透明背景bitmaip
	private boolean mSyn = false;//循环和onDraw同步
	public boolean mIsStop = false;//是否到达指定区域
	
	public NewLayOut(Context context) {
		super(context);
		init(context);
	}
	
	public NewLayOut(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}
	
	private void init(Context context)
	{
		mContext = context;
		mSelecter = new BitmapDrawable(
				BitmapFactory.decodeResource(mContext.getResources(), 
						R.drawable.topbar_select));
		mNowRect = new Rect();
		mEndRect = new Rect();
	}
	
	protected void onLayout(boolean paramBoolean, int paramInt1, int paramInt2, int paramInt3, int paramInt4)
	{
		super.onLayout(paramBoolean, paramInt1, paramInt2, paramInt3, paramInt4);
		this.getChildAt(0).getHitRect(mNowRect);//取得第一个控制区域作为起始区域
	}
	
	/**
	 * 
	 * @param v 目标控件
	 */
	public void doWork(View v)
	{
		v.getHitRect(this.mEndRect);
		
		if (this.mNowRect.right < this.mEndRect.right)
		{
			work(new RunForword()
			{
				public void run()
				{
					mNowRect.left += SPEED;//每次左边移动15格
					mNowRect.right += SPEED;//每次右边移动15格
					
					System.out.println("is run run run");
					
					if (mNowRect.right >= mEndRect.right)//如果移动超出或等于目标区域
						ReachRect();
				}
			});
		}
		else if(this.mNowRect.right > this.mEndRect.right)
		{
			work(new RunForword()
			{
				public void run()
				{
					mNowRect.left -= SPEED;//每次左边移动15格
					mNowRect.right -= SPEED;//每次右边移动15格
					
					if (mNowRect.right <= mEndRect.right)//如果移动超出或等于目标区域
						ReachRect();
				}
			});
		}
	}
	
	private void work(RunForword run)
	{
		this.mIsStop = false;
		while(!this.mIsStop)
		{
			if(this.mSyn)//画图与循环同步
			{
				run.run();
				System.out.println("is running!");
				this.mSyn = false;
				this.postInvalidate();
				//Thread.sleep(35);
			}
		}
	}
	
	/**
	 * 到达目的地
	 */
	private void ReachRect()
	{
		mNowRect.left = mEndRect.left;
		mNowRect.right = mEndRect.right;
		mIsStop = true;
	}
	
	protected void onDraw(Canvas canvas)
	{
		super.onDraw(canvas);
		
		mSelecter.setBounds(mNowRect);
		mSelecter.draw(canvas);
		this.mSyn = true;

		System.out.println("is ondraw");
	}
	
	public interface RunForword
	{
		void run();
	}
}


编写的过程中发现一点问题:

第一:画图与循环同步的问题

private void work(RunForword run)
	{
		this.mIsStop = false;
		while(!this.mIsStop)
		{
			if(this.mSyn)//画图与循环同步
			{
				run.run();
				System.out.println("is running!");
				this.mSyn = false;
				this.postInvalidate();
				//Thread.sleep(35);
			}
		}
	}


如果把 if(this.mSyn) 这段去掉 看图:

QQ顶栏扁圆透明背景移动的实现

就是while循环好多次之后,onDraw才执行一次。猜想onDraw在上一次未执行完之前是不会被执行第二次的(onDraw好像开了一个新线程画图,但看SDK源码实现没看出个端儿。),所以需要做一个这样的同步。这里是继承LinearLayout的,不知道直接继承View会不会出现这种情况。上面的程序,onDraw执行完的时间大概在Thread.sleep(35)这么多时间。

看看把 if(this.mSyn) 加上去后的打印数据 看图:

QQ顶栏扁圆透明背景移动的实现

第二:把移动的运算部份run.run();的方法直接放到onDraw里面运算

private void work(RunForword run)
	{
		this.mIsStop = false;
		while(!this.mIsStop)
		{
			if(this.mSyn)//画图与循环同步
			{

				System.out.println("is running!");
				this.mSyn = false;
				this.postInvalidate();
				//Thread.sleep(35);
			}
		}
	}
protected void onDraw(Canvas canvas)
	{
		super.onDraw(canvas);
		run.run();//大概时这个意思。。当实这样实写是不行的。
		mSelecter.setBounds(mNowRect);
		mSelecter.draw(canvas);
		this.mSyn = true;

		System.out.println("is ondraw");
	}


这样做的话,发觉移动的侦数比较底下,分析了一下原因。首先上面讲的,因为onDraw在上一次未画完图之前,第二次是不会运行的。而while循环又无视onDraw方法未执行完毕。所以在onDraw未执行完毕的过程中。运行run.run(),把下一次移动的数据准备好了。所以侦数就稍有上升了。

最后附上DEMO的源码: test3.rar

如上描述,有不正确的地方,请指教。谢谢。。

完毕。

有关ANDROID QQ的一些实现方法,请听下回分解。
1 楼 offeeyang 2010-08-28  
效果不错啊
2 楼 Czero 2010-09-15  
不错啊,楼主有心
3 楼 huanxisha147 2010-11-05  
不错 我要深入学习 
4 楼 Coding.Ghost 2010-12-16  
进入高级View必须学习的东西。
5 楼 ffshow2006 2011-01-05  
下回分解在哪?要是引用的给个链接啊。
6 楼 binner 2011-03-31  
cool!