Android 实现table切换动画

实现效果如下图:在“首页”和“我的信息”之间切换时,后面的背景从“首页”以动画形式滚动到“我的信息”。 
   
    思路:自定义一个控件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);   
     }  
   
 }  

全部代码请查看附件

http://download.csdn.net/detail/skysahadev/4900713


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值