参考博客http://yanweimin7.iteye.com/blog/1126570 实现,把mNowRect的更新放到Handler里,逻辑更简单。
实现效果如下图:在“首页”和“我的信息”之间切换时,后面的背景从“首页”以动画形式滚动到“我的信息”。
思路:自定义一个控件MoveTab,继承LinearLayout。假设当前选中的控件区域为mNowRect,目标控件区域为mEndRect。我们还需要一个Drawable mDrawable(就是切换过程中移动的图片)。使用Handler更新mNowRect,重写onDraw(),在onDraw()里将Drawable画在mEndRect里,直到mNowRect和mEndRect重合。
因为这里的mDrawable和MoveTab相关性比较大,为了使MoveTab更加通用,我们还使用了attrs.xml,并在其中定义属性move_drawable,和mDrawable相关联。
res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="MoveTab"> <attr name="move_drawable" format="reference" /> </declare-styleable></resources>
在res/layout/main.xml中定义MoveTab时,可以通过下面xml代码指定mDrawable
xmlns:demo="http://schemas.android.com/apk/res/com.ipjmc.demo"...demo:move_drawable="@drawable/home_btn_bg_d" <!--指定mDrawable-->
在布局文件main.xml中,我们使用<com.ipjmc.demo.view.MoveTab></com.ipjmc.demo.view.MoveTab>来指定MoveTab,并在其中添加了5个Button,在外观上和新浪微博的一样
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:demo="http://schemas.android.com/apk/res/com.ipjmc.demo" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:text="@string/hello" android:layout_width="fill_parent" android:layout_height="0px" android:layout_weight="1"/> <com.ipjmc.demo.view.MoveTab android:id="@+id/move_tab" android:background="@drawable/home_btn_bg_n" android:orientation="horizontal" demo:move_drawable="@drawable/home_btn_bg_d" android:layout_width="fill_parent" android:layout_height="wrap_content" > <Button android:tag="radio_button0" android:text="@string/main_home" android:drawableTop="@drawable/icon_home" style="@style/main_tab_bottom" /> <Button android:tag="radio_button1" android:text="@string/main_news" android:drawableTop="@drawable/icon_meassage" style="@style/main_tab_bottom" /> <Button android:tag="radio_button2" android:text="@string/main_my_info" android:drawableTop="@drawable/icon_selfinfo" style="@style/main_tab_bottom" /> <Button android:tag="radio_button3" android:text="@string/menu_search" android:drawableTop="@drawable/icon_square" style="@style/main_tab_bottom" /> <Button android:tag="radio_button4" android:text="@string/more" android:drawableTop="@drawable/icon_more" style="@style/main_tab_bottom" /> </com.ipjmc.demo.view.MoveTab></LinearLayout>
MoveTab的定义,具体代码如下:
package com.ipjmc.demo.view;import com.ipjmc.demo.R;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.util.Log;import android.view.View;import android.widget.LinearLayout;public class MoveTab extends LinearLayout { private static final int DELAY = 10; private static final int SPEED = 16; private static final int MOVE = 1; private static final String TAG = "MoveTab"; private Context mContext; private Drawable mDrawable;//移动的背景图 private final Rect mNowRect = new Rect();//当前的区域 private final Rect mEndRect = new Rect();//结束的区域 private final Handler mHandler = new Handler() { public void handleMessage(Message msg) { if (msg.what == MOVE) { //如果还没有到达目标区域,就延迟DELAY后,重新绘图 if (!move()) { this.sendEmptyMessageDelayed(MOVE, DELAY); } } }; }; public MoveTab(Context context) { super(context); init(context, null); } public MoveTab(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } private void init(Context context, AttributeSet attrs) { mContext = context; TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.MoveTab); //通过XML中定义的属性"move_drawable",生成mDrawable mDrawable = attr.getDrawable(R.styleable.MoveTab_move_drawable); if (mDrawable == null) { Log.e(TAG, "Errorr : mDrawable == null"); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //默认选择第一个table,把它的区域设置为mNowRect this.getChildAt(0).getHitRect(mNowRect); super.onLayout(changed, l, t, r, b); } /** * 对外公开的接口,外部调用者应该在table被点击时调用它,将mDrawable移动到目标控件v * @param 目标控件 */ public void selectTab(View v) { //将目标控件v的区域设置为mEndRect v.getHitRect(mEndRect); if (mNowRect.right != mEndRect.right) { mHandler.sendEmptyMessage(MOVE); //向Handler发送消息,开始移动mDrawable } } /** * 重新计算图片的位置 * @return 动画是否结束 */ private boolean move() { int direction = 0; //已非常接近目标控件, 直接让mNowRect和mEndRect重合 if (Math.abs(mNowRect.left - mEndRect.left) <= SPEED) { mNowRect.left = mEndRect.left; mNowRect.right = mEndRect.right; invalidate(); return true; } if (mNowRect.left < mEndRect.left) { direction = 1; //向右 } else { direction = -1; //向左 } //更新mNowRect mNowRect.left += SPEED * direction; mNowRect.right += SPEED * direction; //请求onDraw() invalidate(); return false; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (null != mDrawable) { //将mDrawable画到mNowRect上 mDrawable.setBounds(mNowRect); mDrawable.draw(canvas); Log.i(TAG, "onDraw : " + mNowRect.left + ", " + mNowRect.right + ", " + mNowRect.top + ", " + mNowRect.bottom); } else { Log.e(TAG, "Errorr : mDrawable == null"); } }}
MoveDrawableActivity.java 文件
package com.ipjmc.demo;import com.ipjmc.demo.view.MoveTab;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.CompoundButton;import android.widget.CompoundButton.OnCheckedChangeListener;import android.widget.RadioButton;import android.widget.RadioGroup;public class MoveDrawableActivity extends Activity implements OnClickListener{ private static final String TAG = "MoveTab"; private RadioGroup mRadioGroup; private Button mButton[]; private MoveTab mMoveTab; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i(TAG, "onCreate"); setContentView(R.layout.main); mMoveTab = (MoveTab) findViewById(R.id.move_tab); initRadios(); } private void initRadios() { mButton = new Button[5]; String tag = "radio_button"; for (int i = 0; i < mButton.length; i++) { mButton[i] = (Button) mMoveTab.findViewWithTag(tag+i); //通过tag查找View mButton[i].setOnClickListener(this); } } @Override public void onClick(View v) { //点击后,开始动画 mMoveTab.selectTab(v); }}
全部代码请查看附件