`
ipjmc
  • 浏览: 707113 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android 实现table切换动画

阅读更多
    参考博客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); 
	}

}


全部代码请查看附件
  • 大小: 10.9 KB
  • 大小: 10.7 KB
分享到:
评论

相关推荐

    Android左右切换动画

    通过上述步骤,你就能实现类似QQ2012 TableHost的左右切换动画效果。记得在实际开发中根据需求调整动画时长、动画类型以及触发切换的条件,以达到最佳的用户体验。在项目中使用TableFlipperExample这个示例代码,...

    Android代码-ExpandTable

    在Android开发中,"ExpandTable"是一个常见的需求,特别是在构建类似58同城这样的信息分类列表时,用户可能需要点击一个条目来展开更多的详细信息。这个项目实现了这种点击展开的效果,利用了Android的基础布局组件`...

    smartTable.zip

    4. **国际化与适配**:smartTable支持多语言切换,只需提供不同的语言资源文件。同时,根据屏幕尺寸和方向进行适配,保证在不同设备上的良好显示效果。 五、总结 smartTable作为一款优秀的Android表格框架,其强大...

    Android开发之TableHost控件经典实例

    在Android开发中,TableHost控件可能并非标准的Android SDK内置控件,但根据标题和描述,我们可以推测这里提到的TableHost可能是开发者自定义或者是一个特定库提供的组件,用于实现类似表格布局或视图切换的功能。...

    android 仿微信界面 ViewPager+Fragment

    这个资源专注于利用`ViewPager`和`Fragment`来构建这样的界面,这两种组件是Android SDK中的核心组件,用于实现动态和交互性强的用户界面。接下来,我们将深入探讨这两个组件以及如何结合使用它们来创建一个仿微信的...

    android layout 简单例子

    7. CoordinatorLayout:这是一种高级布局,用于实现复杂的交互和动画效果,如滑动隐藏顶部栏或底部导航栏。它利用布局行为(Layout Behaviors)使子视图能够响应触摸事件或系统状态改变。 8. ConstraintLayout:这...

    Android应用开发入门教程

    第1章 Android的系统介绍5 1.1 系统介绍5 1.2 软件结构和使用的工具7 第2章 Android SDK的开发环境10 2.1 Android SDK的结构10 2.2 Android SDK环境安装11 2.2.1. 安装JDK基本Java环境11 ...10.4 3D动画效果的实现129

    android AllLayoutDemo

    9. **栈布局(StackView/ViewSwitcher)**:这类布局常用于实现滑动切换效果,如卡片堆叠,可以包含多个子视图,一次只显示一个。 10. **螺旋布局(Gallery)**:已弃用的布局,以前用于创建轮播效果,现在可以使用...

    listview 分页,tablehost 实现,滑动手势, navigation bar

    此外,还可以使用`FragmentTransaction`的`setCustomAnimations()`方法为不同页面间的切换添加动画效果。 以上四个知识点在Android应用开发中扮演着核心角色,理解并熟练运用它们能够提升应用的用户体验和性能。在...

    android备忘录

    3. **SQLite数据库操作**:要实现备忘录的增删查改功能,需要编写SQL语句,包括CREATE TABLE用于创建数据库表,INSERT INTO用于添加新备忘,SELECT查询备忘,UPDATE更新已有备忘,以及DELETE删除备忘。 4. **...

    Android开发技巧合集

    **横竖屏切换不销毁当前Activity**:在AndroidManifest.xml中为对应的Activity设置`android:configChanges="orientation|screenSize"`属性即可。 ##### 2.2 INTENTRECEIVER `IntentReceiver`是用于接收系统或其他...

    Android技术面试整理-葵花宝典

    - **Tween动画**:这类动画通过修改视图的属性来实现平滑的过渡效果,如位置、大小、透明度等。适用于实现较为简单的视觉效果,如淡入淡出、缩放等。 - **Frame动画**:Frame动画通过连续播放一系列预先准备好的帧...

    Android 布局

    同时,随着Android版本的更新,新的布局工具和特性不断出现,如`ConstraintLayout`的`MotionLayout`扩展,使动态动画设计变得更加简单。 总之,理解并熟练掌握Android的各种布局方式是创建高效、美观且适应性强的...

    android 笔试题集锦

    1. **Tween动画**:这种动画通过改变视图组件的位置、大小和透明度等属性来实现动画效果,而无需重新绘制图像。适用于简单的动画效果,如淡入淡出、缩放等。 2. **Frame动画**:这种动画类似于电影播放,通过连续...

    android考试知识点考试.doc

    它常用于实现动画效果,与Fragment一起使用。 4. **PercentFrame/RelativeLayout**:百分比布局允许开发者基于父布局的百分比来设置控件的大小,避免了硬编码尺寸的问题,实现灵活的平分布局。使用前需要添加对应的...

    Android例子源码健康养生类应用效果集合.zip

    1. **侧滑导航(Slide Navigation)**:在移动应用设计中,侧滑菜单通常用于实现主界面与导航菜单之间的切换,提供一种简洁的多层级导航方式。在这个例子中,开发者可能使用了Android的SlidingDrawer或Navigation...

    底布突起导航栏 凸起table

    综上所述,"底布突起导航栏"的实现涉及到多个Android开发技术,包括自定义视图、布局设计、事件处理、动画效果、图标更换、Fragment切换、设备适配和触摸反馈等。通过掌握这些技术,开发者可以创建出符合设计需求且...

    无缝连接可循环滚动布局

    1. **重写测量和布局**:为了实现可循环滚动,`ForeverLayout`需要知道所有子视图的大小和位置,以便在滚动到边界时能够无缝切换到下一个或上一个元素。这涉及到对`onMeasure()`和`onLayout()`方法的重写。 2. **...

Global site tag (gtag.js) - Google Analytics