Android tabhost+侧滑菜单

           项目已经告一段落,从中总结一下自己学习到的知识。一开始的项目ui框架采用的tabhost,在第一版完成时,老板提出加入侧滑菜单,其实就是将某一个tab页作为菜单滑出。现在网上有各种侧滑菜单的实现方法以及类库,但考虑到项目已经成型,实在不想改动ui框架,便在原来的基础上使用ValueAnimator来进行布局的移动来达到侧滑菜单的效果,如下截图。

   

Android tabhost+侧滑菜单_第1张图片Android tabhost+侧滑菜单_第2张图片

    图中的“tab3”原本是一个tab页,现作为右侧菜单的触发按钮,当"tab3"选中时,底部的tab栏向左滑动(中间的内容区域保持不变),同时右侧菜单滑出。

TabActivity的布局代码如下

 
        

    
    

  
 
        
        
  
     
        
  
                
                
                
                       
        
       



 
        
        

com.example.slidingmenu.ContentLayout   为自定义的tab内容页布局,由于当菜单滑出时,移动的只是底部的tab栏而不是整个tab页面的移动,即右侧菜单是覆盖在内容页上面,当右侧菜单上有点击事件时,事件会向下传递,会触发到内容页中相应的事件。故在右侧菜单滑出时,需要拦截右侧菜单事件的传递。

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
public class ContentLayout extends LinearLayout{
	private boolean isRight=false;//右侧菜单是否打开标识
	private float position;
	public float getPosition() {
		return position;
	}
	public void setPosition(float position) {
		this.position = position;
	}
	public boolean isRight() {
	return isRight;
	}
	public void setRight(boolean right) {
		this.isRight = right;
	}
	public ContentLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}
	public ContentLayout(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		if(isRight()){
			if(ev.getAction()== MotionEvent.ACTION_DOWN){
				  setPosition(ev.getX());//设置点击坐标,便于判断是点击的是否为非右侧菜单区域,若是,这将右侧菜单关闭
			}
			return true;//右菜单打开,拦截内容页上的点击事件
		}
		return false;
		
	}
}


在tabactivity中,使用ValueAnimator的子类ObjectAnimator,为需要移动的布局设置相应的动画属性

ValueAnimator bounceAnim = ObjectAnimator.ofFloat(rightLayout, "x",window_width, window_width/3).setDuration(300);//右侧菜单滑出
bounceAnim.setInterpolator(new LinearInterpolator());//匀速运动
bounceAnim.start();
右侧菜单关闭,只需调用
bounceAnim.reverse();

注意: ValueAnimator是在api 11才添加,低版本的api无法使用,对于低版本采用设置view在屏幕上的位置来实现,但在本例中未加入移动动画效果。
ValueAnimator
tabactivity的全部代码:
public class MainActivity extends TabActivity {
	    private final static int MOVE_DISTANCE = 80;

	    private float mPositionX;
		private RadioGroup group;
	
		private TabHost host;
	private ContentLayout contentLayout;//内容页即tab切换页
	    private Context  mContext;
	    private RadioButton tab1,tab2;
	    private CheckBox tab3;
	    private TabSpec spec1,spec2, spec3;
	    private RelativeLayout main;
	    private LinearLayout rightLayout;
	    private LinearLayout leftLayout;/*左边底部tab*/
	    private ValueAnimator bounceAnim = null,bouAnimator1=null;//api 11以上才能使用
		  private boolean isRight=false;//右边菜单是否滑出标志
			private int window_width;// 屏幕的宽度	
		@SuppressWarnings("deprecation")
		@Override
		protected void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			setContentView(R.layout.activity_main);
			mContext=this;
			window_width=getResources().getDisplayMetrics().widthPixels;//获取手机屏幕宽
			main=(RelativeLayout) findViewById(R.id.main);
			rightLayout=(LinearLayout) findViewById(R.id.right_layout);
			leftLayout=(LinearLayout) findViewById(R.id.left_layout);
		
		        rightLayout.setOnTouchListener(mOnTouchListener);
		        main.setOnTouchListener(mOnTouchListener);
	
			host = getTabHost();
			tab1=(RadioButton) findViewById(R.id.tab1);
			tab2=(RadioButton) findViewById(R.id.tab2);
			tab3=(CheckBox) findViewById(R.id.tab3);
			tab3.setChecked(isRight);
		
			
			tab3.setOnClickListener(new OnClickListener() {
				public void onClick(View v) {
					initMoveLayout();
				}
			});
		contentLayout=(ContentLayout) findViewById(R.id.content_layout);
			group = (RadioGroup) findViewById(R.id.radiogroupbutton);
			spec1 =host.newTabSpec("tab1").setIndicator("tab1").setContent(
					new Intent(this, ContentActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
		host.addTab(spec1);
		     host.setCurrentTab(0);
			group.setOnCheckedChangeListener(new OnCheckedChangeListener() {
				@SuppressLint("NewApi")
				@Override
				public void onCheckedChanged(RadioGroup group, int checkedId) {
					switch (checkedId) {
					case R.id.tab1://	
					host.setCurrentTabByTag("tab1");
						break;
					case R.id.tab2 :
						host.setCurrentTabByTag("tab2");
						break;
					}	
				}
				});
		}
		/**
		 * 右边菜单滑出
		 */
		@TargetApi(Build.VERSION_CODES.HONEYCOMB)
		@SuppressLint("NewApi")
		private void initMoveLayout() {
			//API level 11
			if(Build.VERSION.SDK_INT >= 11){
				if(!isRight){
				 	rightLayout.setVisibility(View.VISIBLE);
					 moveLayout();
				}else{
					isRight = false;
					bounceAnim.reverse();
					bouAnimator1.reverse();
				}
	        }else{
	        	if(!isRight){
	        	rightLayout.setVisibility(View.VISIBLE);
	       
	        	RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) leftLayout
						.getLayoutParams();
	        	layoutParams.leftMargin= -window_width+window_width/3;
				leftLayout.setLayoutParams(layoutParams);
				RelativeLayout.LayoutParams rightLayoutParams = (RelativeLayout.LayoutParams) rightLayout
						.getLayoutParams();
				rightLayoutParams.leftMargin=window_width/3;
				rightLayout.setLayoutParams(rightLayoutParams);
			
				  isRight = true;
				}else{
					
					RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) leftLayout
							.getLayoutParams();
		        	layoutParams.leftMargin=0;
					leftLayout.setLayoutParams(layoutParams);
					RelativeLayout.LayoutParams rightLayoutParams = (RelativeLayout.LayoutParams) rightLayout
							.getLayoutParams();
					rightLayoutParams.leftMargin= window_width;
					
					rightLayout.setLayoutParams(rightLayoutParams);
				
					  isRight = false;
				}    
	        }
			contentLayout.setRight(isRight);
		}
		@TargetApi(Build.VERSION_CODES.HONEYCOMB)
		@SuppressLint("NewApi")
		private void moveLayout() {
			if (bounceAnim == null) {
			bounceAnim = ObjectAnimator.ofFloat(rightLayout, "x",window_width, window_width/3).setDuration(300);
			bounceAnim.setInterpolator(new LinearInterpolator());//匀速运动
		}if(bouAnimator1==null){
			bouAnimator1 = ObjectAnimator.ofFloat(leftLayout, "x",0,-window_width+window_width/3).setDuration(300);
			bouAnimator1.setInterpolator(new LinearInterpolator());//匀速运动
		}
		bouAnimator1.start();
		bounceAnim.start();
		isRight = true;
		}
	    @Override
	    protected void onResume() {
	        super.onResume();
	    }
	    @Override
	    protected void onPause() {
	        super.onPause();
	    }
	    /**
	     * 滑动监听
	     * 若是右侧菜单上的touch事件,当手指移动距离在一定范围内,则关闭菜单
	     * 若是非右侧菜单上的touch事件,则关闭菜单
	     */
	    private OnTouchListener mOnTouchListener = new OnTouchListener() {
	        @Override
	        public boolean onTouch(View v, MotionEvent event) {
	        	
	        	  if(v.getId()==R.id.main){
	        		   if(event.getAction()==MotionEvent.ACTION_DOWN&&isRight&&(contentLayout.getPosition()MOVE_DISTANCE&&isRight){
	                        	touchmove();
	                        }

	                     
	                        break;
	                }
	                return true;
	            } 
	            return false;
	        }
	    };
	    /**
	     * 隐藏右边菜单
	     */
		@SuppressLint("NewApi")
		@TargetApi(Build.VERSION_CODES.HONEYCOMB)
		private void touchmove() {
			//ValueAnimator  是在api 11才添加,低版本的api暂通过设置布局view在屏幕上的位置来实现,可自行加入动画
			if(Build.VERSION.SDK_INT >= 11){
			bounceAnim.reverse();
			bouAnimator1.reverse();
	  			}else{

				RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) leftLayout
						.getLayoutParams();
				layoutParams.leftMargin=0;
				leftLayout.setLayoutParams(layoutParams);
				RelativeLayout.LayoutParams rightLayoutParams = (RelativeLayout.LayoutParams) rightLayout
						.getLayoutParams();
				rightLayoutParams.leftMargin= window_width;
				
				rightLayout.setLayoutParams(rightLayoutParams);
				
			}
			isRight = false;
		tab3.setChecked(isRight);
			contentLayout.setRight(isRight);
		}
	  
	}


官网api说明:

public static ObjectAnimator ofFloat (Object target, String propertyName, float... values)

Added in  API level 11

Constructs and returns an ObjectAnimator that animates between float values. A single value implies that that value is the one being animated to. Two values imply a starting and ending values. More than two values imply a starting value, values to animate through along the way, and an ending value (these values will be distributed evenly across the duration of the animation).

Parameters
target The object whose property is to be animated. This object should have a public method on it called setName(), where name is the value of thepropertyName parameter.
propertyName The name of the property being animated.
values A set of values that the animation will animate between over time.
Returns
  • An ObjectAnimator object that is set up to animate between the given values.







你可能感兴趣的:(Android tabhost+侧滑菜单)