QQ顶栏椭圆透明背景移动的实现!
先看ANDROID QQ截图:
再看DEMO截图:
直接看代码:
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;//移动的半透明背景bitmaipprivate 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) 这段去掉 看图:

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

第二:把移动的运算部份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!