Android自定义控件

优酷菜单制作主要技术是RotateAnimation滚动动画



MainActivity.java

package com.youku.manu;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.RelativeLayout;

public class MainActivity extends Activity implements OnClickListener{
	
	private RelativeLayout findViewById1;
	private RelativeLayout findViewById2;
	private RelativeLayout findViewById3;
	
	boolean isLevel3Display = true;
	boolean isLevel2Display = true;
	boolean isLevel1Display = true;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//l初始化View
		initViews();
	}

	private void initViews() {
		//点击事件
		findViewById(R.id.id_home).setOnClickListener(this);
		findViewById(R.id.id_menu).setOnClickListener(this);
		//初始化RelativeLayout
		findViewById1 = (RelativeLayout)findViewById(R.id.rl_level1);
		findViewById2 = (RelativeLayout)findViewById(R.id.rl_level2);
		findViewById3 = (RelativeLayout)findViewById(R.id.rl_level3);
		
	}

	//按钮测试
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		//keyCode事件码
		Log.v("liwangjiang", "keyCode="+keyCode);
		if(AnimationUtils.runingAnimationCount>0){
			//就是当有动画正在执行的时候,取消当前事件
			return true;
		}
		if(keyCode==82){
			if(isLevel1Display){
				if(isLevel2Display){
					AnimationUtils.rotateOutAnim(findViewById2,100);
					isLevel2Display=false;
				}
				if(isLevel3Display){
					AnimationUtils.rotateOutAnim(findViewById3,0);
					isLevel3Display=false;
				}
				AnimationUtils.rotateOutAnim(findViewById1,300);
				isLevel1Display=false;
			}else{
				AnimationUtils.rotateInAnim(findViewById1,0);
				AnimationUtils.rotateInAnim(findViewById2,150);
				AnimationUtils.rotateInAnim(findViewById3,300);
				isLevel1Display=true;
				isLevel2Display=true;
				isLevel3Display=true;
			}
			
		}
		
		return super.onKeyDown(keyCode, event);
	}
	
	
	@Override
	public void onClick(View v) {
		if(AnimationUtils.runingAnimationCount>0){
			//就是当有动画正在执行的时候,取消当前事件
			return;
		}
		switch (v.getId()) {
		case R.id.id_home:
			long delay=0;
			if(isLevel2Display){
				if(isLevel3Display){//如果第三级菜单显示的话标把他设为隐藏
					AnimationUtils.rotateOutAnim(findViewById3,0);
					isLevel3Display = false;
					delay=200;
				}
				AnimationUtils.rotateOutAnim(findViewById2,delay);
				
				isLevel2Display = false;
				
				
			}else{
				AnimationUtils.rotateInAnim(findViewById2,0);
				isLevel2Display = true;
			}
			break;
			
			
		case R.id.id_menu:
			if(isLevel3Display){//三级菜单是默认显示的
				//如果当前三级菜单已经显示,转出去
				AnimationUtils.rotateOutAnim(findViewById3,0);
				isLevel3Display = false;
			}else{
				//如果当前三级菜单没有显示,转出来
				AnimationUtils.rotateInAnim(findViewById3,0);
				isLevel3Display = true;
			}
			break;

		default:
			break;
		}
	}
}

AnimationUtils.java

package com.youku.manu;

import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.RotateAnimation;
import android.widget.RelativeLayout;

public class AnimationUtils {
	public static int runingAnimationCount;
	public static void rotateOutAnim(RelativeLayout layout,long delay){
		
		int childCount = layout.getChildCount();//得到子节点
		//如果隐藏,则找到所有的子View,吧子View禁用
		for(int i=0;i<childCount;i++){
			layout.getChildAt(i).setEnabled(false);//false表示禁用  true表示启动
		}
		
		
		RotateAnimation ra = new RotateAnimation(
				0f, -180,//开始  ,  结束的角度
				Animation.RELATIVE_TO_SELF, 0.5f, //相对的x坐标点(指定旋转中心x值)
				Animation.RELATIVE_TO_SELF, 1.0f);//相对的y坐标点(指定旋转中心y值)
				ra.setDuration(500);//运动的毫秒数
				ra.setFillAfter(true);//设置动画停留在结束位置
				ra.setStartOffset(delay);//设置动画开始延长
				
				ra.setAnimationListener(new Listener());
				
				layout.startAnimation(ra);
	}
	public static void rotateInAnim(RelativeLayout layout,long delay){
		
		int childCount = layout.getChildCount();//得到子节点
		//如果隐藏,则找到所有的子View,吧子View禁用
		for(int i=0;i<childCount;i++){
			layout.getChildAt(i).setEnabled(true);//false表示禁用  true表示启动
		}
		
		RotateAnimation ra = new RotateAnimation(
				-180f, 0,//开始  ,  结束的角度
				Animation.RELATIVE_TO_SELF, 0.5f, //相对的x坐标点(指定旋转中心x值)
				Animation.RELATIVE_TO_SELF, 1.0f);//相对的y坐标点(指定旋转中心y值)
				ra.setDuration(500);//运动的毫秒数
				ra.setFillAfter(true);//设置动画停留在结束位置
				ra.setStartOffset(delay);//设置动画开始延长
				ra.setAnimationListener(new Listener());
				layout.startAnimation(ra);
	}
	
	static class Listener implements AnimationListener{

		@Override
		public void onAnimationStart(Animation animation) {//开始动
			runingAnimationCount++;
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onAnimationEnd(Animation animation) {//结束动作
			// TODO Auto-generated method stub
			runingAnimationCount--;
		}

		@Override
		public void onAnimationRepeat(Animation animation) {//重复动
			// TODO Auto-generated method stub
			
		}
		
	}
}


activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >
	<RelativeLayout 
	    android:id="@+id/rl_level1"
	    android:layout_width="100dp"
	    android:layout_height="50dp"
	    android:layout_alignParentBottom="true"
	    android:layout_centerHorizontal="true"
	    android:background="@drawable/level1">
	    <ImageButton 
	        android:id="@+id/id_home"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:background="@null"
	        android:layout_centerInParent="true"
	        android:src="@drawable/icon_home"/>
	    
	</RelativeLayout>
	
	<RelativeLayout 
	    android:id="@+id/rl_level2"
	    android:layout_width="175dp"
	    android:layout_height="85dp"
	    android:layout_alignParentBottom="true"
	    android:layout_centerHorizontal="true"
	    android:background="@drawable/level2">
	    <ImageButton 
	        android:id="@+id/id_menu"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:background="@null"
	        android:layout_centerHorizontal="true"
	        android:layout_marginTop="5dp"
	        android:src="@drawable/icon_menu"/>
	    
	    
	       <ImageButton 
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:background="@null"
	       	android:layout_alignParentBottom="true"
	       	android:layout_marginLeft="5dp"
	        android:src="@drawable/icon_search"/>
	       
	       <ImageButton 
	           android:layout_width="wrap_content"
	           android:layout_height="wrap_content"
	           android:background="@null"
	           android:layout_alignParentRight="true"
	           android:layout_alignParentBottom="true"
	           android:layout_marginRight="5dp"
	           android:src="@drawable/icon_myyouku"/>
	</RelativeLayout>
	
	<RelativeLayout 
	    android:id="@+id/rl_level3"
	    android:layout_width="265dp"
	    android:layout_height="130dp"
	    android:layout_alignParentBottom="true"
	    android:layout_centerHorizontal="true"
	    android:background="@drawable/level3">
	    <ImageButton 
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:background="@null"
	        android:layout_alignParentBottom="true"
	        android:layout_marginLeft="5dp"
	        android:src="@drawable/channel1"/>
	    
	    
	     <ImageButton 
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:background="@null"
	        android:layout_alignParentBottom="true"
	        android:layout_marginLeft="25dp"
	        android:layout_marginBottom="40dp"
	        android:src="@drawable/channel2"/>
	     
	     
	       <ImageButton 
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:background="@null"
	        android:layout_alignParentBottom="true"
	        android:layout_marginLeft="55dp"
	        android:layout_marginBottom="75dp"
	        android:src="@drawable/channel3"/>
	       
	       <ImageButton 
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:background="@null"
	      	android:layout_centerHorizontal="true"
	   		android:layout_marginTop="5dp"
	        android:src="@drawable/channel4"/>
	       
	       <ImageButton 
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:background="@null"
	      	android:layout_alignParentRight="true"
	      	android:layout_marginRight="58dp"
	      	android:layout_marginTop="20dp"
	        android:src="@drawable/channel6"/>
	       
	       <ImageButton 
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:background="@null"
	      	android:layout_alignParentRight="true"
	      	android:layout_marginRight="28dp"
	      	android:layout_marginTop="60dp"
	        android:src="@drawable/channel7"/>
	       
	       
	       <ImageButton 
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:background="@null"
	        android:layout_alignParentBottom="true"
	      	android:layout_alignParentRight="true"
	      	android:layout_marginRight="10dp"
	        android:src="@drawable/channel7"/>
	</RelativeLayout>
</RelativeLayout>

图片资源:按钮自定义  随便找一些资源




轮番广告图主要技术:android.support.v4.view.ViewPager 

图片资源自给找    

在使用ViwePager之前一定要导入一个包android-support-v4.jar




MainActivity.java

package com.liufangguanggao.image;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;

public class MainActivity extends Activity implements OnPageChangeListener{
	    private ViewPager viewPager;  //对应的viewPager  
	    int[] imageResIds;
	    ArrayList<ImageView> listImage;
	    LinearLayout ll_point_container;
	    
	    String[] contentData;//显示的文本
	    
	    TextView textView;//显示的文本
	    
	    int lastPosition;
	    
	    
	    boolean isLoop=true;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		//初始化布局View视图
		initView();
		
		//Model数据
		initData();
		
		//Controller控制器
		initAdapter();
		
		
		
		//开启轮番图
		new Thread(){
			public void run() {
				while(isLoop){
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
					runOnUiThread(new Runnable() {
						
						@Override
						public void run() {
							viewPager.setCurrentItem(viewPager.getCurrentItem()+1);//不能在子线程里面更新UI
						}
					});
					//条到下一个页面去
				}
			};
		}.start();
	}
	@Override
	public void onBackPressed() {
		isLoop=false;
		super.onBackPressed();
	}
	private void initView() {
		
		viewPager=(ViewPager)findViewById(R.id.viewpager);
		//viewPager.setOffscreenPageLimit(2);表示左右各新建2个   默认表示左右各建1个
		ll_point_container=(LinearLayout)findViewById(R.id.ll_point_container); 
	
		viewPager.setOnPageChangeListener(this);//设置接听器
		textView=(TextView)findViewById(R.id.textViewId);//初始化文本编辑
		
		
		
	}
	@Override
	protected void onDestroy() {
		isLoop=false;
		super.onDestroy();
	}
	private void initData() {
		//初始化要显示的数据
		
		//图片数组id资源
		 imageResIds = new int[]{R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e};
		 
		//文本描述
		 contentData = new String[]{
				"这位37岁的牙买加老将具备夺取世界冠军",
				"当奥蒂今晚闪着泪花走出第六届",
				"世界田径锦标赛赛场时,她追求了一生的梦想化作了一场噩梦。",
				"奥蒂已经赢得过一次百米冠军。",
				"可以说,没有任何一个"
		};
		 
		 
		 //初始化图片
		 listImage = new ArrayList<ImageView>();
		 ImageView imageView;
		 View pointView;
		 LayoutParams linear;
		 for(int i=0;i<imageResIds.length;i++){
			 imageView = new ImageView(this);
			 imageView.setBackgroundResource(imageResIds[i]);
			 listImage.add(imageView);
			 
			 //加小白点
			 pointView = new View(this);
			 pointView.setBackgroundResource(R.drawable.selector_bg_point);
			 linear= new LinearLayout.LayoutParams(15, 15);//设置圆的大小
			 if(i!=0)
			 linear.leftMargin=30;
			 pointView.setEnabled(false);//吧该把你
			 ll_point_container.addView(pointView,linear);
		 }
		
	}
	private void initAdapter() {
		//设置适配器
		ll_point_container.getChildAt(0).setEnabled(true);//表示选中的位置  就是白点选中的位置  初始化白点
		textView.setText(contentData[0]);
		lastPosition=0;
		
		
		viewPager.setAdapter(new PagerAdapter() {
			
			@Override
			public int getCount() {
				// TODO Auto-generated method stub
				return Integer.MAX_VALUE;//listImage.size()表示有几项滑动  Integer.MAX_VALUE表示一个很大的数
			}
			//3.指定复用的判断逻辑  固定写法
			@Override
			public boolean isViewFromObject(View view, Object object) {
			//当划到新的条目,又返回来,view是否可以被复用
				//返回判断规则
				return view==object;
			}
			
			
			//1.返回要显示的条目内容,创建条目
			@Override
			public Object instantiateItem(ViewGroup container, int position) {
				//container 容器:ViewPager
				//position  :当前要显示的条目容器的位置
				Log.v("wang", "初始化条目");
				int newPosition=position%listImage.size();
				ImageView imageView=listImage.get(newPosition);//position这里如果想我想循环的换必须判断或取余
				//1.吧View添加的container中
				container.addView(imageView);
				//2.吧View对象返回给框架,适配器
				return imageView;//必须重写,否则报异常
			}

			//2.销毁条目
			@Override
			public void destroyItem(ViewGroup container, int position, Object object) {
				//object 要销毁的对象
				Log.v("wang", "销毁对象"+position);
				container.removeView((View)object);
			}
			
			
		});
		
		
		//默认设置到中间的某个位置
		//int pos=Integer.MAX_VALUE/2-(Integer.MAX_VALUE/2%listImage.size());
		viewPager.setCurrentItem(500000);//设置跳到某个位置
	}

	
	//方法重新  接听器
	
	
	//滚动状态变化调用
	@Override
	public void onPageScrollStateChanged(int state) {
		
	}
	//滚动的时候调用
	@Override
	public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
		
	}
	//当新的条目被选中的时候调用
	@Override
	public void onPageSelected(int position) {
		int newPosition=position%listImage.size();//防止越界
		
		textView.setText(contentData[newPosition]);
		
		ll_point_container.getChildAt(lastPosition).setEnabled(false);//表示选中的位置  就是白点选中的位置
		ll_point_container.getChildAt(newPosition).setEnabled(true);//表示选中的位置  就是白点选中的位置
		
		lastPosition=newPosition;//记录上次的位置
	}
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >
    
    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_height="160dp">
        
		<android.support.v4.view.ViewPager  
		    android:id="@+id/viewpager"  
		    android:layout_width="match_parent"  
		    android:layout_height="match_parent"  
		    android:layout_gravity="center" /> 
		<LinearLayout 
		    android:layout_width="match_parent"
		    android:layout_height="40dp"
		    android:padding="5dp"
		    android:orientation="vertical"
		    android:gravity="center_horizontal"
		    android:layout_alignParentBottom="true"
		    android:background="#66000000">
		    <TextView 
		        android:id="@+id/textViewId"
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content"
		        android:textColor="@android:color/white"
		        android:singleLine="true"
		        />
		    <LinearLayout 
		        android:layout_width="match_parent"
		        android:id="@+id/ll_point_container"
		        android:layout_height="wrap_content"
		        android:orientation="horizontal"
		        android:gravity="center_horizontal"
		        >
		        
		    </LinearLayout>
		    
		</LinearLayout>        
    </RelativeLayout>
 
</RelativeLayout>
 
 




下拉列表主要技术是使用:PopupWindow  类

点击打开链接   PopupWindow  介绍



MainActivity.java

package com.xianlaxuankuang.selectWindown;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener,OnItemClickListener{
	ListView listView;
	EditText editText;
	List<String> list;
	PopupWindow popupWindow;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		findViewById(R.id.button).setOnClickListener(this);
		editText=(EditText)findViewById(R.id.eidtTextId);
		list = new ArrayList<String>();
	}
	//重写点击事件
	@Override
	public void onClick(View v) {
		showPopupWindow();
	}
	
	private void showPopupWindow() {
		initListView();
		//显示下拉选择框
		popupWindow=new PopupWindow(listView, editText.getWidth(), 300);
		
		//设置点击外部区域,自动隐藏
		popupWindow.setOutsideTouchable(true);	//外部可触摸
		popupWindow.setBackgroundDrawable(new BitmapDrawable());//设置一个空的背景,响应点击事件
		popupWindow.setFocusable(true);//设置可获取焦点
		//指定在哪个控件下面
		popupWindow.showAsDropDown(editText, 0, -10);
	}
	private void initListView() {
		listView = new ListView(this);
		for(int i=0;i<30;i++){
			list.add(10000+i+"");
		}
		
		listView.setBackgroundResource(R.drawable.listview_background);//设置背景图片
		listView.setAdapter(new MyAdapter());
		
		
		
		listView.setOnItemClickListener(this);
	}
	
	class MyAdapter extends BaseAdapter{

		@Override
		public int getCount() {
			return list.size();
		}

		@Override
		public Object getItem(int position) {
			// TODO Auto-generated method stub
			return list.get(position);
		}

		@Override
		public long getItemId(int position) {
			// TODO Auto-generated method stub
			return position;
		}

		@Override
		public View getView(final int position, View convertView, ViewGroup parent) {
			View view;
			if(convertView==null){
				view=View.inflate(parent.getContext(), R.layout.item_nuber, null);
			}else{
				view=convertView;
			}
			TextView textView=(TextView)view.findViewById(R.id.textViewId);
			textView.setText(list.get(position));
			ImageButton button=(ImageButton)view.findViewById(R.id.image_delete);
			button.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					list.remove(position);
					
					notifyDataSetChanged();//更新见面
					
					if(list.size()==0){
						popupWindow.dismiss();//如果删除的是最后一条那么把该popupWindow隐藏
					}
				}
			});
			return view;
		}
		 
	}

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
		editText.setText(list.get(position));
		popupWindow.dismiss();
	}
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

   <RelativeLayout 
       android:layout_width="200dp"
       android:layout_centerHorizontal="true"
       android:layout_height="match_parent">
       <EditText 
           android:id="@+id/eidtTextId"
           android:layout_width="match_parent"
           android:layout_height="50dp"
           />
       <ImageButton 
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:id="@+id/button"
           android:background="@null"
           android:padding="10dp"
           android:layout_alignParentRight="true"
           android:src="@drawable/down_arrow"/>
   </RelativeLayout>

</RelativeLayout>

item_nuber.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:descendantFocusability="blocksDescendants"
    android:gravity="center_vertical"
    android:orientation="horizontal" >
    <!-- android:descendantFocusability="blocksDescendants"  -->
    <!-- 表示区块点击  -->
    <ImageView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/user"/>
    <TextView 
        android:layout_width="0dp"
        android:layout_weight="1"
        android:id="@+id/textViewId"
        android:layout_height="wrap_content"
        />
	<ImageButton 
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content"
	    android:id="@+id/image_delete"
	   	android:padding="10dp"
	    android:background="@null"
	    android:src="@drawable/delete"/>
</LinearLayout>



自定义开关:主要技术是  View  继承View   自己给化出来








MainActivity.java
package com.zidingyi.openOff;

import com.zidingyi.openOff.ToggleView.onSwitchStateUpdateListener;

import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;


public class MainActivity extends Activity {

	ToggleView toggleView;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		toggleView = (ToggleView)findViewById(R.id.toggleView);
		//设置背景颜色
		toggleView.setSwitchBackgroundResource(R.drawable.switch_background);
		//设置滑动按钮
		toggleView.setSlideButtonResource(R.drawable.slide_button);
		//设置开关的状态
		toggleView.setSwitchState(false);
		
		toggleView.setOnSwichStateUpdateListener(new onSwitchStateUpdateListener() {
			
			public void onStateUpdate(boolean state) {
				Toast.makeText(MainActivity.this, "State "+state, Toast.LENGTH_LONG).show();
			}
		});
	}
}

ToggleView.java

package com.zidingyi.openOff;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;


/**
 * 自定义开关
 * @author Lenovo
 * 
 * Android 的界面绘制流程
 *  测量   		   摆放  		 绘制
 * measure  ->  layout  ->   draw
 *    |			  |			   |
 * onMeasure -> onLayout ->  onDraw  重写这些方法,实现自定义控件
 * 
 * 他们对应  两个继承关系   View 和	ViewGroup  他们是有区别的
 * View
 * onMeasure() (在这个方法里指定自己的宽高) ->  onDraw()   (绘制自己的内容)
 * 
 * ViewGroup
 * onMeasure() (定义自己的宽高,还有子View的宽高) -> onLayout()  (摆放所有的子View) ->  onDraw()  (绘制自己的内容)
 * 
 */
public class ToggleView extends View{
	/**
	 * 用于在xml里面使用,可指定自定义属性,如果指定了样式,则走该构造函数
	 * @param context
	 * @param attrs
	 * @param defStyleAttr
	 */
	
	
	Bitmap switchBackgroupBitmap;
	Bitmap slideButtonBitmap;
	Paint paint;//创建画笔
	private boolean mSwitchState=false;
	float currentX;
	public ToggleView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}
	/**
	 * 用于在xml里面使用   , 可指定自定义属性
	 * @param context
	 * @param attrs  之定义属性
	 */
	public ToggleView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}
	/**
	 * 用于代码创建控件
	 * @param context
	 */
	public ToggleView(Context context) {
		super(context);
	
		init();
	}
	
	
	private void init() {
		 paint = new Paint();		
	}
	//设置背景图片
	public void setSwitchBackgroundResource(int switchBackground) {
		switchBackgroupBitmap = BitmapFactory.decodeResource(getResources(), switchBackground);
	}
	//设置按钮图片
	public void setSlideButtonResource(int slideButton) {
		slideButtonBitmap = BitmapFactory.decodeResource(getResources(), slideButton);
	}
	//设置按钮状态
	public void setSwitchState(boolean mSwitchState) {
		this.mSwitchState = mSwitchState;
		
	}
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		//设置View的大小
		setMeasuredDimension(switchBackgroupBitmap.getWidth(), switchBackgroupBitmap.getHeight());
		
	}
	//canvas画布,画布 ,在上边绘制的内容都会显示到界面上
	@Override
	protected void onDraw(Canvas canvas) {
		Paint paint = new Paint();
		//1.绘制背景
		canvas.drawBitmap(switchBackgroupBitmap, 0, 0, paint);
		if(isTouchMode){//判断状态
			//根据当前用户触摸到的位置画滑块
			float newLeft = currentX-slideButtonBitmap.getWidth()/2.0f;
			//让滑动向左移动自身一半大小的位置
			//限定滑块范围
			if(newLeft<0){
				newLeft=0;//左边范围
			}else if(newLeft>switchBackgroupBitmap.getWidth()-slideButtonBitmap.getWidth()){
				newLeft=switchBackgroupBitmap.getWidth()-slideButtonBitmap.getWidth();//右边范围
			}
			canvas.drawBitmap(slideButtonBitmap, newLeft, 0,paint);
		}else{
			//2.绘制滑块
			//根据开关状态,直接设置图片位 置
			if(mSwitchState){//打开
				int newLift=switchBackgroupBitmap.getWidth()-slideButtonBitmap.getWidth();
				canvas.drawBitmap(slideButtonBitmap, newLift, 0, paint);
			}else{//关闭
				canvas.drawBitmap(slideButtonBitmap, 0, 0, paint);
			}
		}
		
		
		
	}
	boolean isTouchMode=false;//设置滑动状态
	private onSwitchStateUpdateListener swichStateUpdateListener;
	//重写触摸事件,响应用户的触摸
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN://鼠标点下
			Log.v("wang", "ACTION_DOWN:按下");
			currentX = event.getX();//得到当前点击的X坐标
			isTouchMode=true;//按下状态设为true
			break;
		case MotionEvent.ACTION_MOVE://鼠标移动  表示按下移动
			Log.v("wang", "ACTION_MOVE移动");
			currentX = event.getX();//得到当前点击的X坐标
			break;
		case MotionEvent.ACTION_UP://鼠标点击松开
			Log.v("wang", "ACTION_UP松开");
			isTouchMode=false;
			currentX = event.getX();//得到当前点击的X坐标
			
			
			//根据当前按下的位置,和控件中心的位置进行比较
			float center = switchBackgroupBitmap.getWidth()/2.0f;
			boolean state=currentX>center;
			
			if(swichStateUpdateListener!=null&&state!=mSwitchState){
				swichStateUpdateListener.onStateUpdate(!state);
			}
			
			mSwitchState=state;
			break;
		default:
			break;
		}
		
		invalidate();//会引发OnDraw()调用,里边的变量会重新生效见面会重新更新
		
		return true;//消费了用户的触摸事件,才可以收到其他事件
	}

	public interface onSwitchStateUpdateListener{
		//状态回调,吧当前状态传出去
		void onStateUpdate(boolean state);
	}

	public void setOnSwichStateUpdateListener(onSwitchStateUpdateListener SwichStateUpdateListener) {
		swichStateUpdateListener = SwichStateUpdateListener;
	}
}

activity_main.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <com.zidingyi.openOff.ToggleView
        android:id="@+id/toggleView"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
       />

</RelativeLayout>
 
 


下拉刷新列表继承ListView自己画




MainActivity.java
package com.down.ListViewTable;

import java.util.ArrayList;
import java.util.List;

import com.down.ListViewTable.RefreshListView.OnRefershListener;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class MainActivity extends Activity {
	RefreshListView mListView;
	List<String> mList;
	MyAdapter adapter;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉页面头部的标题
		setContentView(R.layout.activity_main);
		mListView=(RefreshListView)findViewById(R.id.listViweId);
		
		mList = new ArrayList<String>();
		//设置接听
		mListView.setRefershListener(new OnRefershListener() {
			
			@Override
			public void OnRefersh() {
				new Thread(){
					public void run() {
						try {
							Thread.sleep(3000);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					mList.add(0, "刷新出来的数据");
					
					runOnUiThread(new Runnable() {
						
						@Override
						public void run() {
							adapter.notifyDataSetChanged();
							mListView.onRefreshComplete();//更新完数据之后吧头部信息隐藏起来
						}
					});
					};
				}.start();
			}

			@Override
			public void loadMoreData() {
				new Thread(){
					public void run() {
						try {
							Thread.sleep(3000);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					mList.add("加载更多数据.......");
					mList.add("加载更多数据.......");
					mList.add("加载更多数据.......");
					mList.add("加载更多数据.......");
					
					runOnUiThread(new Runnable() {
						
						@Override
						public void run() {
							adapter.notifyDataSetChanged();
							mListView.onRefreshComplete();//更新完数据之后吧头部信息隐藏起来
						}
					});
					};
				}.start();				
			}
		});
		
		for(int i=0;i<30;i++){
			mList.add("ListView的第"+(i+1)+"条数据");
		}
		 adapter = new MyAdapter();
		mListView.setAdapter(adapter);
	}
	
	class MyAdapter extends BaseAdapter{

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			TextView text = new TextView(parent.getContext());
			text.setTextSize(18f);
			text.setText(""+mList.get(position));
			return text;
		}
		
		@Override
		public int getCount() {
			return mList.size();
		}

		@Override
		public Object getItem(int position) {
			return mList.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

	}
	
}


RefreshListView.java


package com.down.ListViewTable;

import java.text.SimpleDateFormat;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import android.widget.TextView;

public class RefreshListView extends ListView implements OnScrollListener{
	View mHeaderView;
	float downY;
	float moveY;
	float upY;
	int measuredHeight;
	float paddingTop;
	public static final int PULL_REFRESH=0;//下拉刷新
	public static final int RELEASE_REFRESH=1; //释放刷新
	public static final int REFRESHING=2;	//正在刷新
	private int currentState=PULL_REFRESH;//当前刷新模式
	RotateAnimation rotateUpAnimation;
	RotateAnimation rotateDownAnimation;
	
	
	//初始化头部控件
	View mHeaderArrow;
	TextView mHeaderTitle;
	TextView mHeaderLastData;
	View mPd;
	private OnRefershListener onListener;
	//脚步布局
	View mFooterView;
	//是否影藏脚布局
	boolean isLoadMore;
	//得到控件的高度
	int footerHeight;
	public RefreshListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public RefreshListView(Context context) {
		super(context);
		init();
	}

	public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}
	
	/**
	 * 初始化头布局  , 脚布局
	 * 滚动接听
	 */
	private void init() {
		//初始化头布局
		initHeaderView();
		
		//初始化动画
		initAnimation();
		
		//初始化脚布局
		initFooterView();
		
		//初始化策划接听器
		setOnScrollListener(this);
	}
	/**
	 * 初始化脚布局
	 */
	private void initFooterView() {
		mFooterView = View.inflate(getContext(), R.layout.layout_footer_list, null);
		mFooterView.measure(0, 0);//测量
	
		footerHeight = mFooterView.getMeasuredHeight();//得到该控件的高度
		
		mFooterView.setPadding(0, -footerHeight, 0, 0);
		
		addFooterView(mFooterView);
	}

	/**
	 * 初始化动画
	 */
	private void initAnimation() {
		//向上转 , 围绕着自己的中心逆时针 0-->-180度
	
		rotateUpAnimation = new RotateAnimation(0f, -180,
				Animation.RELATIVE_TO_SELF, 0.5f,
				Animation.RELATIVE_TO_SELF, 0.5f);
		rotateUpAnimation.setDuration(1000);//旋转时间
		rotateUpAnimation.setFillAfter(true);//动画停留在结束位置
	
		
		//向下转  , 围绕着自己的中心逆时针 -180-->-360度
		
			rotateDownAnimation = new RotateAnimation(-180, -360,
					Animation.RELATIVE_TO_SELF, 0.5f,
					Animation.RELATIVE_TO_SELF, 0.5f);
			rotateUpAnimation.setDuration(1000);//旋转时间
			rotateUpAnimation.setFillAfter(true);//动画停留在结束位置
	}

	/**
	 * 初始化头部局
	 */
	private void initHeaderView() {
		mHeaderView = View.inflate(getContext(), R.layout.layout_header_list, null);
		mHeaderArrow = mHeaderView.findViewById(R.id.iv_arrow);
		mHeaderTitle = (TextView)mHeaderView.findViewById(R.id.tv_title);
		mHeaderLastData = (TextView)mHeaderView.findViewById(R.id.tv_desc_last_refresh);
		
		mPd = mHeaderView.findViewById(R.id.pd);
		//提前手动测量 
		mHeaderView.measure(0, 0);//按照设置的测量规则
		
		//在这里如果直接mHeaderView.getHeight();是拿不到高度的因为该布局没有加载
		measuredHeight = mHeaderView.getMeasuredHeight();//测量后的高度
		
		mHeaderView.setPadding(0,-measuredHeight , 0, 0);
		//在设置数据适配器之前执行添加  头布局/脚布局  的方法   脚布局mListView.addFooterView(v);
		addHeaderView(mHeaderView);//头部添加
	}
	
	//触摸事件
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		//判断滑动距离,给Header设置paddingTop
		float offset = 0;
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN://按下
			downY = ev.getY();
			break;
		case MotionEvent.ACTION_MOVE://滑动
			moveY = ev.getY();
			//滑动时显示上面的View
			 offset = moveY-downY;//移动的偏移量
			//如果是正在刷新中,就执行父类的处理
			 if(currentState == REFRESHING){
				 return super.onTouchEvent(ev);
			 }
			//只有    偏移量>0 , 并且当前第一个可见条目索引为0的才显示
			if(offset>0&&getFirstVisiblePosition()==0){
				//重新设置头部跟着触摸的事件跑
				paddingTop = -measuredHeight+offset;//显示的内容
				mHeaderView.setPadding(0,(int)paddingTop , 0, 0);
				
				//变成释放刷新
				if(paddingTop>=0&¤tState!=RELEASE_REFRESH){//如果paddingTop>0的话表示全部显示     //头部局完全显示
					//切换成释放刷新
					currentState=RELEASE_REFRESH;
					updateHeader();
				}else if(paddingTop<=0&¤tState!=PULL_REFRESH){  //不完全显示    表示在状态变换的时候调用
					//切换成系列新模式
					currentState=PULL_REFRESH;
					updateHeader();//根据最新的的状态值更新头布局内容
				}
				return true;//当前事件被我们处理消费
			}
			
			break;
		case MotionEvent.ACTION_UP://松开
			upY = ev.getY();
			//mHeaderView.setPadding(0, -measuredHeight, 0, 0);//隐藏头部显示的
			
//			if(paddingTop<0){
//				//-paddingTop < 0不完全显示 , 恢复
//				mHeaderView.setPadding(0, -measuredHeight, 0, 0);
//			}else{
//				//paddingTop >= 完全显示,执行正在刷新...
//				currentState=REFRESHING;
//				updateHeader();
//			}
			//可以根据刚刚设置的状态判断
			if(currentState == PULL_REFRESH){
				//-paddingTop < 0不完全显示 , 恢复
				mHeaderView.setPadding(0, -measuredHeight, 0, 0);
			}else if(currentState==RELEASE_REFRESH){
				//paddingTop >= 完全显示,执行正在刷新...
				currentState=REFRESHING;
				updateHeader();
			}
			break;
	
		}
	
		
		return super.onTouchEvent(ev);
	}
	//更新头部方法
	private void updateHeader() {
		switch (currentState) {
		case PULL_REFRESH://下拉刷新
			mHeaderArrow.startAnimation(rotateDownAnimation);
			mHeaderTitle.setText("下拉刷新");
			break;

		case RELEASE_REFRESH://释放刷新
			//做动画,改变标题
			mHeaderArrow.startAnimation(rotateUpAnimation);
			mHeaderTitle.setText("释放刷新");
			
			break;
		case REFRESHING://正在刷新
			mHeaderArrow.clearAnimation();//清除动画
			mHeaderArrow.setVisibility(View.INVISIBLE);//隐藏图片
			mPd.setVisibility(View.VISIBLE);//吧加载图片显示出来
			mHeaderTitle.setText("释放刷新中...");
			if(onListener != null){
				onListener.OnRefersh();//通知调用者,让网络加载更多数据...
			}
			
			break;
		}
	}
	interface OnRefershListener{
		//下拉刷新
		void OnRefersh();
		//加载更多数据
		void loadMoreData();
	}
	//当某个事件调用的时候触发到MainActivity
	public void setRefershListener(OnRefershListener  onListener) {
		this.onListener = onListener;
		
	}

	public void onRefreshComplete() {
		if(isLoadMore){
			mFooterView.setPadding(0, -footerHeight, 0, 0);
			isLoadMore=false;
		}else{
			currentState = PULL_REFRESH;//更新完数据改变状态
			mHeaderTitle.setText("下拉刷新");//切换文本
			mHeaderView.setPadding(0, -measuredHeight, 0, 0);//影藏头布局
			mPd.setVisibility(View.INVISIBLE);//隐藏圆圈
			mHeaderView.setVisibility(View.VISIBLE);//显示下拉图片
			
			String time = getTime();
			mHeaderLastData.setText("最后刷新时间:"+time);//改变时间
		}
		
		
	}

	private String getTime() {
		long currentTime=System.currentTimeMillis();//获取当前时间
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		return format.format(currentTime);
	}
	
	
	//策划接听
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		//状态更新的时候
		//scrollState表示状态   0  表示空闲   1  触摸滑动  2 滑翔  
		//public static int SCROLL_STATE_IDLE = 0; // 表示空闲
		//public static int SCROLL_STATE_SCROLL = 1;//触摸滑动
		//public static int SCROLL_STATE_FLING = 2;//滑翔  
		//最新状态是空闲状态,并且当前界面显示了所有数据的最后一条数据,就加载更多
		if(scrollState == SCROLL_STATE_IDLE && getLastVisiblePosition() >= (getCount()-1)){
			//显示脚布局
			mFooterView.setPadding(0, 0, 0, 0);
			
			isLoadMore = true;
			setSelection(getCount());//跳转的最后一条,使其显示出加载更多
			onListener.loadMoreData();
		}
	}

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
		//滑动过程
		
	}
}

activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

   	<com.down.ListViewTable.RefreshListView 
   	    android:layout_width="wrap_content"
   	    android:layout_height="wrap_content"
   	    android:id="@+id/listViweId"></com.down.ListViewTable.RefreshListView>

</RelativeLayout>

layout_footer_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:padding="5dp"
    android:gravity="center"
    android:layout_height="match_parent" >
  
        <ProgressBar 
            android:id="@+id/pd"
            android:layout_width="50dp"
            android:layout_height="50dp"
           android:indeterminateDrawable="@drawable/shape_progress"
            />
   
	    <TextView 
	        android:id="@+id/tv_title"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
			android:textColor="#ff0000"
			android:layout_marginLeft="20dp"
			android:textSize="16sp"
	        android:text="下拉刷新"/>
	        
</LinearLayout>

layout_header_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:padding="5dp"
    android:layout_height="match_parent" >
    <FrameLayout 
        android:layout_width="50dp"
        android:layout_height="50dp">
        <ImageView 
            android:id="@+id/iv_arrow"
            android:layout_width="wrap_content"
            android:layout_gravity="center"
            android:layout_height="wrap_content"
            android:src="@drawable/common_listview_headview_red_arrow"/>
        <ProgressBar 
            android:id="@+id/pd"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="invisible"
           android:indeterminateDrawable="@drawable/shape_progress"
            />
    </FrameLayout>
	<LinearLayout 
	    android:layout_width="match_parent"
	    android:layout_height="wrap_content"
	    android:gravity="center_horizontal"
	    android:orientation="vertical"
	    >
	    <TextView 
	        android:id="@+id/tv_title"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
			android:textColor="#ff0000"
			android:textSize="16sp"
	        android:text="下拉刷新"/>
	        <TextView 
	         android:id="@+id/tv_desc_last_refresh"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:layout_marginTop="5dp"
			android:textColor="#666"
			android:textSize="14sp"
	        android:text="最后刷新时间  2018-4-24"/>
	</LinearLayout>
</LinearLayout>

shape_progress.xml

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android" 
    android:fromDegrees="0"
    android:pivotX="50%" 
    android:pivotY="50%"
    android:toDegrees="-360">
    <!--  android:fromDegrees="0"从哪里开始转 -->
    <!--  android:pivotX="50%" android:pivotY="50%"圆的围着哪一个点转 -->
	<!-- android:toDegrees="-360"从哪里开始转到哪里结束 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
    android:shape="ring"
    android:innerRadius="20dp"
    android:thickness="5dp"
    android:useLevel="false"><!-- 指定圆环 -->
    <!-- android:innerRadius="20dp"内圆半径 -->
    <!--  android:thickness="5"v圆框的厚度 -->
  
    <gradient android:type="sweep"
        android:startColor="#ff0000"
        android:centerColor="#44ff0000"
        android:endColor="#00000000"/>
  <!-- android:type="sweep" -->
</shape>

</rotate>




侧滑面板主要技术用了继承ViewGroup



MainActivity.java


package com.cehuanliebiao.chlb;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;

public class MainActivity extends Activity implements OnClickListener{
	SlideManu sm;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		sm=(SlideManu)findViewById(R.id.slideManu);
		
		 findViewById(R.id.imageButtonId).setOnClickListener(this);;
	}
	
	
	public void onTabClick(View view){
		
	}


	@Override
	public void onClick(View v) {
		sm.switchState();		
	}
}


SlideManu.java


package com.cehuanliebiao.chlb;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;
/**
 * 
 * @author Lenovo
 测量			 摆放		绘制
  measure	->	layout	->	draw
  	  | 		  |			 |
  onMeasure -> onLayout -> onDraw 重写这些方法, 实现自定义控件
  
  都在onResume()之后执行
  
  View流程
  onMeasure() (在这个方法里指定自己的宽高) -> onDraw() (绘制自己的内容)
  
  ViewGroup流程
  onMeasure() (指定自己的宽高, 所有子View的宽高)-> onLayout() (摆放所有子View) -> onDraw() (绘制内容)
 
 */
public class SlideManu extends ViewGroup{
	//移动坐标
	float downX=0;
	float moveX=0;
	public static final int MAIN_STATE=0;//显示主面板
	public static final int MENU_STATE=1;//显示菜单面板
	private int currentState=MAIN_STATE ;//当前状态
	private Scroller scroller;
	public SlideManu(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initData();
	}

	public SlideManu(Context context, AttributeSet attrs) {
		super(context, attrs);
		initData();
	}

	public SlideManu(Context context) {
		super(context);
		initData();
	}
	
	private void initData() {
		//初始化滚动器 , 数值模拟器
		scroller = new Scroller(getContext());
	}

	//指定宽高
	/**
	 * 测量并设置 所有子View的宽高
	 * widthMeasureSpec 当前控件的宽度测量规则
	 * heightMeasureSpec 当前控件的高度测量规则
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		//测量左面板的宽度
		View leftMenu;  
		View mainContent;
		leftMenu = getChildAt(0);
		leftMenu.measure(leftMenu.getLayoutParams().width, heightMeasureSpec);
		
		//测量右面板的宽高
		mainContent = getChildAt(1);
		mainContent.measure(widthMeasureSpec, heightMeasureSpec);
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}
	/**
	 * changed :当前控件的尺寸大小 , 位置是否发生变化
	 * left:    当前控件  左边距
	 * top:		当前控件  顶边距
	 * right:	当前控件  右边距
	 * bottom:	当前控件  下边距
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		//摆放内容,左面板
		View leftMenu = getChildAt(0);
		leftMenu.layout(-leftMenu.getMeasuredWidth(), 0, 0, b);
	
		//摆放主面板
		View mainContent = getChildAt(1);
		mainContent.layout(l, t, r, b);
	}
	/**
	 * 触摸事件
	 * scrollTo(x, y);//表示移动到x或y的坐标点   		当前位置跳到某个位置
	 * scrollBy(x, y);//表示当前的x或y的坐标点累加  	原理的基础上滚动
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
	
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN://按下
			downX=event.getX();
			break;
		case MotionEvent.ACTION_MOVE://移动
			moveX = event.getX();
			
			//将要发生的偏移量/变化量
			int scrollX = (int) (downX-moveX);
			
			/**
			 * 		getScrollX()含义
			 * ①当界面为初始界面时,只要界面没有移动,无论点屏幕哪个位置,getScrollX()输出始终为0。
			 * ②当手向右滑动时,藏在屏幕左边的view也慢慢露出来,这时getScrollX()输出的值慢慢由0向负数方向走。
			 * ③当左边的view都出现时,点击屏幕任意位置,这时getScrollX()输出的值也固定了,我这里的值为-733。
			 * ④这时当手向左边滑动时,getScrollX()输出的值将从-733向0靠近,直到界面为初始化时,getScrollX()输出的值为0。
			 * 
			 */
			//计算将要滚动到的位置,判断是否会超出 ,超出去了不执行scrollBy
			int newScrollPosition=getScrollX() + scrollX;//getScrollX()表示滑动View的X轴
			if(newScrollPosition < -getChildAt(0).getMeasuredWidth()){//限定左边界
				//  < -240
				scrollTo(-getChildAt(0).getMeasuredWidth(), 0);
			}else if(newScrollPosition > 0){//限定右边界
				//>0
				scrollTo(0, 0);
			}else{
				//变换偏移量生效
				scrollBy(scrollX, 0);
				
			}
			
			
			downX=moveX;
			break;
		case MotionEvent.ACTION_UP://松开
			//根据当前滚动到的位置,和左面板的一半进行比较
			int leftCenter = (int)(-getChildAt(0).getMeasuredWidth()/2);
			if(getScrollX()<leftCenter){
				//打开 ,切换成菜单面板
				currentState = MENU_STATE;
				updateCurrentContent();
			}else{
				//关闭,切换成主面板
				currentState = MAIN_STATE;
				updateCurrentContent();
			}
			break;

		default:
			break;
		}
		
		return true;//消费事件  如果是自己玩去定义的一个View或ViewGroup就返回true
	}
	/**
	 * 根据当前的状态,执行  关闭/开启  的动画
	 */
	private void updateCurrentContent() {
		int startX = getScrollX();
		int dx=0;
		//平滑滚动
		if(currentState==MENU_STATE){
			//打开菜单
			//dx = 结束位置(-240)   -  开始位置
			dx = -getChildAt(0).getMeasuredWidth()-startX;
		}else{
			//打开主面板
			dx=0-startX;
		}
		//startX 开始的x值
		//startY 开始的y值
		//dx	 将要发生的水平变化量,移动的x距离
		//dy	 将要发生的垂直变化量,移动的y距离
		//duration 数据模拟持续的时长
		int duration=Math.abs(dx*5);
		scroller.startScroll(startX, 0, dx, 0, duration);
		invalidate();//重回界面
	}
	//维持动画的继续
	@Override
	public void computeScroll() {
		super.computeScroll();
		if(scroller.computeScrollOffset()){
			//true , 动画还没有结束
			//获取当前模拟的数据,也就是要滚动到的位置
			int currX = scroller.getCurrX();
			scrollTo(currX, 0);//滚过去
			
			invalidate();//重绘界面
		}
	}
	public void open(){
		currentState = MENU_STATE;
		updateCurrentContent();
	}
	public void close(){
		currentState = MAIN_STATE;
		updateCurrentContent();
	}
	public void  switchState(){
		if(currentState==MAIN_STATE){
			open();
		}else{
			close();
		}
	}

}


activity_main.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

   <com.cehuanliebiao.chlb.SlideManu
       android:id="@+id/slideManu" 
       android:layout_width="match_parent"
       android:layout_height="match_parent">
     	<!-- 保函一个页面   -->
       <include layout="@layout/layout_left_menu"/>
       
       
       <include layout="@layout/layout_main_content"/>
   </com.cehuanliebiao.chlb.SlideManu>

</RelativeLayout>

layout_left_menu.xml


<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="240dp"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:background="@drawable/menu_bg"
        android:orientation="vertical" >

        <TextView
            style="@style/styleName"
            android:drawableLeft="@drawable/tab_news"
            android:text="新闻" />
        <TextView
            style="@style/styleName"
            android:drawableLeft="@drawable/tab_read"
            android:text="订阅" />
         <TextView
            style="@style/styleName"
            android:drawableLeft="@drawable/tab_local"
            android:text="本地" />
         <TextView
            style="@style/styleName"
            android:drawableLeft="@drawable/tab_ties"
            android:text="跟帖" />
         <TextView
            style="@style/styleName"
            android:drawableLeft="@drawable/tab_vote"
            android:text="图片" />
         <TextView
            style="@style/styleName"
            android:drawableLeft="@drawable/tab_focus"
            android:text="话题" />
          <TextView
            style="@style/styleName"
            android:drawableLeft="@drawable/tab_vote"
            android:text="投票" />
        <TextView
            style="@style/styleName"
            android:drawableLeft="@drawable/tab_ugc"
            android:text="聚会阅读" />
    </LinearLayout>

</ScrollView>


layout_main_content.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff"
    android:orientation="vertical" >
    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:background="@drawable/top_bar_bg">
        <ImageButton 
            android:id="@+id/imageButtonId"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@null"
            android:src="@drawable/main_back"/>
        <View 
            android:layout_width="2dp"
            android:layout_height="match_parent"
            android:background="@drawable/top_bar_divider"/>
    	<TextView 
    	    android:layout_width="wrap_content"
    	    android:layout_height="wrap_content"
    	    android:textColor="#fff"
    	    android:layout_gravity="center_vertical"
    	    android:layout_marginLeft="30dp"
    	    android:textSize="30sp"
    	    android:text="网易新闻"/>
    </LinearLayout>
<TextView 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:textSize="30sp"
    android:text="网易新闻侧滑列表往左滑"/>
</LinearLayout>

selector_manu_bt_bg.xml


<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_pressed="true" android:drawable="@color/bt_bg_pressed"></item>
    
	<item android:drawable="@android:color/transparent"></item>
</selector>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="bt_bg_pressed">#33ADCFD6</color>

</resources>

styles.xml
<resources>

    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="android:Theme.Light">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.
        -->
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
    </style>
    <style name="styleName" parent="android:Widget.Holo.Light.TextView">
        <item name="android:clickable">true</item>
        <item name="android:drawablePadding">10dp</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:padding">8dp</item>
        <item name="android:textColor">#ADCFD6</item>
        <item name="android:textSize">18sp</item>
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:onClick">onTabClick</item>
        <item name="android:background">@drawable/selector_manu_bt_bg</item>
    </style>
</resources>

猜你喜欢

转载自blog.csdn.net/qq_35427437/article/details/80095093