andriodApp 引导界面的制作

      大家好 我是akira 前面学了那么多的零碎 你是不是觉得有点无聊了呢 不要紧 今天咱来点有意思的 

自己动作搞一个软件的引导界面 什么是引导界面 我们看下以下几个图你就知道了 


当然 以上图我只是反编译了一下某app的 我们通常在用的时候 都发现有这么些东西 有些引导页面没有下面的点 有些有 

最后进行点击进入home 注意 这里在手机第一次安装app的时候有引导 在下一次进入的时候 是直接跳到home中去的 

好了 我们想知道的就是这么多 

咱来分析一下 

这里我将引入一个新的控件叫做viewPager 因为通常情况下做引导界面有两种方式 过去的andriod3.0之前没有viewPager时可能更麻烦些 

1 是使用我们即将要使用的viewPager来做 2是使用一个开源的框架叫做ViewFlow 这个有兴趣的可以搜下 

OK 我们在分析一点就是 无论这几个图怎么动始终有三个东西1 背景图 2 那几个小圆点 当然 这个app偷了个懒 实际上大多数app使用的是动态加载

shape的方法 第三个就是两个状态的按钮 没错就这么多 分析了这么多之后 我们来动手写布局 写代码 

先来一个简单的 也就是 我们只要四张图 其他的都可以不用管 

布局文件 

<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=".MainActivity" >

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</RelativeLayout>

这里就是相对布局套用一个viewPager 这里注意下 问了兼容性 咱都采用v4的包 而既然是控件那么肯定有宽高 宽高均为填充父窗体

我们看下主要的代码

public class GideActivty extends Activity {
	
	private ViewPager pager;
	private List<ImageView> images;
	private ImageAdater adater;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		//设置无标题和全屏
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(R.layout.activity_gide);
		findview();
		initData();
	}
	/**
	 * 初始化数据
	 */
	private void initData() {
		images = new ArrayList<ImageView>();
		ImageView im1 = new ImageView(this);
		im1.setBackgroundResource(R.drawable.welcome_intro_0);
		ImageView im2 = new ImageView(this);
		im2.setBackgroundResource(R.drawable.welcome_intro_1);
		ImageView im3 = new ImageView(this);
		im3.setBackgroundResource(R.drawable.welcome_intro_2);
		ImageView im4 = new ImageView(this);
		im4.setBackgroundResource(R.drawable.welcome_intro_3);
		images.add(im1);
		images.add(im2);
		images.add(im3);
		images.add(im4);
		adater = new ImageAdater(images);
		pager.setAdapter(adater);
	}

	private void findview() {
		pager = (ViewPager) findViewById(R.id.vp);
		
	}
	
	private class ImageAdater extends PagerAdapter{
		
		
		private List<ImageView> ims;
		
		
		
		public ImageAdater(List<ImageView> images) {
			this.ims = images;
		}

		@Override
		public void destroyItem(ViewGroup container, int position, Object object) {
			((ViewPager)container).removeView(ims.get(position));
//			super.destroyItem(container, position, object);
		}

		@Override
		public Object instantiateItem(ViewGroup container, int position) {
			((ViewPager)container).addView(ims.get(position), 0);
			return ims.get(position);
		}

		@Override
		public int getCount() {
			// TODO Auto-generated method stub
			return ims.size();
		}

		@Override
		public boolean isViewFromObject(View arg0, Object arg1) {
			// TODO Auto-generated method stub
			return arg0==arg1;
		}
		
		
		
	}

}

这里代码比较长 我来具体说明一下 首先你肯定要拿到控件 findview 

接下来先不管别的 我们要知道一点 既然是ViewPager 那么就会有适配器 问题来了 什么是适配器 

这个就好比比如我现在手里有一个港版的iphone6 但我知道 

港版的电器充电器在大陆是无法适应的 因此你需要买一个旧标的插线板或者是转换头 

这种东西就是一种适配器 现在你只要看成是一个加工车间就好了 是viewPager的加工车间

ok 这里我们有了适配器 adapter 接下来 有一点就是 viewpager的自定义adapter最好都是继承PagerAdapter的 

很显然 PagerAdapter是一个抽象类 那么好 我们实现它的方法 

eclipse有一点不智能就是 实际上起作用的并不是 getCount 和 isViewFromObject 而是 

前两个 一个是添加 一个是销毁 很显然 我们添加一个 再滑动后肯定要销毁 那么OK 知道了这点 

我们再看下adapter的代码解析

private class ImageAdater extends PagerAdapter{
		
		
		private List<ImageView> ims;
		
		
		
		public ImageAdater(List<ImageView> images) {
			this.ims = images;
		}

		@Override
		public void destroyItem(ViewGroup container, int position, Object object) {
			((ViewPager)container).removeView(ims.get(position));
//			super.destroyItem(container, position, object);
		}

		@Override
		public Object instantiateItem(ViewGroup container, int position) {
			((ViewPager)container).addView(ims.get(position), 0);
			return ims.get(position);
		}

		@Override
		public int getCount() {
			// TODO Auto-generated method stub
			return ims.size();
		}

		@Override
		public boolean isViewFromObject(View arg0, Object arg1) {
			// TODO Auto-generated method stub
			return arg0==arg1;
		}
		
		
		
	}

这里我是用一个私有内部类 当然你也可以更规范的做法 建一个包 命为adapter 然后把代码放进去 导包完成 这都OK的 

我想说的不是这个 我们现在的目的是动态的去加载图 那么怎么加载呢利用原有的经验是在xml上设置background 但是这样在动态操作的时候效果是不好的 

而且 andriod本身是利用反射机制去调用图的 所以更好的做法是代码 

因为是图 所以是ImageView(以下简称iv) 那么我们观察iv的构造不难发现 里面是有个上下文的 而我们在设置的时候 跟背景异曲同工 

有个方法是 setBackgroundResource 里面传的就是你的图 知道这个 你不难理解这个方法的意义

/**
	 * 初始化数据
	 */
	private void initData() {
		images = new ArrayList<ImageView>();
		ImageView im1 = new ImageView(this);
		im1.setBackgroundResource(R.drawable.welcome_intro_0);
		ImageView im2 = new ImageView(this);
		im2.setBackgroundResource(R.drawable.welcome_intro_1);
		ImageView im3 = new ImageView(this);
		im3.setBackgroundResource(R.drawable.welcome_intro_2);
		ImageView im4 = new ImageView(this);
		im4.setBackgroundResource(R.drawable.welcome_intro_3);
		images.add(im1);
		images.add(im2);
		images.add(im3);
		images.add(im4);
		adater = new ImageAdater(images);
		pager.setAdapter(adater);
	}

接下来 我们要思考 我们如何让适配器知道这里有几张图 并且显示呢 

最简单的办法无非是构造传参 这个太熟悉了 于是就有了传入list的做法 

而既然有了值 那么getCount 就不难理解了 而isViewObject 这个要怎么理解呢 

我认为 这就好比是1图和2图在滑动的时候 系统会做一个判断 因为你不一定全部滑到2 也不一定全部走出1 所以系统要知道这是不是同一个view在

我们这里可以理解为同一个图 

于是乎 就有了下面更精确的说法

功能:该函数用来判断instantiateItem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是代表的同一个视图(即它俩是否是对应的,对应的表示同一个View)

返回值:如果对应的是同一个View,返回True,否则返回False。

绿字摘自http://blog.csdn.net/harvic880925/article/details/38487149 

好的 关键的两个方法来了 一个是初始化 一个是销毁 这个它没有生成 但你可以实现其未实现方法中找到 

快捷键 

alt shift +s 找到OrriadeXXX选项 选择方法 我们知道 我们传进来的是list 而list拿对象最方便的是依靠position 

于是乎 我们利用viewGroup的addView方法 就可以完成

((ViewPager)container).addView(ims.get(position), 0);
return ims.get(position);

同理 销毁

((ViewPager)container).removeView(ims.get(position));

对于addView和removeView 现在你有个大概影响 以后我会再讲到 

而viewGroup是方法里传的(你可以理解为装view的架子) 我们要用肯定要强转为ViewPager 

下面 运行一下 效果图如下


下面就是需求中的第二个问题 如何找到按钮控件 

我们发现由于是图 所以很难找到按钮 最好的方法是将按钮分离开来并设置监听 

在viewPager中有onPagerChangeListener 好 我们接下来完善代码

<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=".MainActivity" >

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
    
    <ImageButton 
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="30dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/btnnormal"
        android:contentDescription="@null"
        />

</RelativeLayout>

这里我们发现就加了一个按钮 接下来 我要对这个按钮进行操作 我们加一个id 

 android:id="@+id/ib"

OK 再次回到原来的引导act 这次我们要做的就是判断当前的position是否为最后一个并且改变ib的图标 设置监听

代码如下

public class GideActivty extends Activity implements OnPageChangeListener {
	
	private ViewPager pager;
	private List<ImageView> images;
	private ImageAdater adater;
	private ImageButton ib;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		//设置无标题和全屏
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(R.layout.activity_gide);
		findview();
		initData();
		setListener();
	}
	private void setListener() {
		pager.setOnPageChangeListener(this);
		ib.setClickable(false);
		
	}
	/**
	 * 初始化数据
	 */
	private void initData() {
		images = new ArrayList<ImageView>();
		ImageView im1 = new ImageView(this);
		im1.setBackgroundResource(R.drawable.welcome_intro_0);
		ImageView im2 = new ImageView(this);
		im2.setBackgroundResource(R.drawable.welcome_intro_1);
		ImageView im3 = new ImageView(this);
		im3.setBackgroundResource(R.drawable.welcome_intro_2);
		ImageView im4 = new ImageView(this);
		im4.setBackgroundResource(R.drawable.welcome_intro_3);
		images.add(im1);
		images.add(im2);
		images.add(im3);
		images.add(im4);
		adater = new ImageAdater(images);
		pager.setAdapter(adater);
	}

	private void findview() {
		pager = (ViewPager) findViewById(R.id.vp);
		ib = (ImageButton) findViewById(R.id.ib);
	}
	
	private class ImageAdater extends PagerAdapter{
		
		
		private List<ImageView> ims;
		
		
		
		public ImageAdater(List<ImageView> images) {
			this.ims = images;
		}

		@Override
		public void destroyItem(ViewGroup container, int position, Object object) {
			((ViewPager)container).removeView(ims.get(position));
//			super.destroyItem(container, position, object);
		}

		@Override
		public Object instantiateItem(ViewGroup container, int position) {
			((ViewPager)container).addView(ims.get(position), 0);
			return ims.get(position);
		}

		@Override
		public int getCount() {
			// TODO Auto-generated method stub
			return ims.size();
		}

		@Override
		public boolean isViewFromObject(View arg0, Object arg1) {
			// TODO Auto-generated method stub
			return arg0==arg1;
		}
		
		
		
	}

	@Override
	public void onPageScrollStateChanged(int arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void onPageScrolled(int arg0, float arg1, int arg2) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void onPageSelected(int position) {
		if(position==3){
			//这里监听最后一个页面
			ib.setBackgroundResource(R.drawable.btnen);
			ib.setClickable(true);
			ib.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					startActivity(new Intent(GideActivty.this, MainActivity.class));
				}
			});
		}
		
	}

}

这里各位不要晕 依然还是看修改的代码 我们知道 我们是加了一个按钮的 因为原来的背景我用ps软件全部抠图抠掉了 

现在 我们找到控件 依然是findview 然后设置监听 

ib.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					startActivity(new Intent(GideActivty.this, MainActivity.class));
				}
			});

这是采用了另一种设置监听的方式 俗称传匿名内部类 或者接口 

然后依然是实现方法 不通的是 我们要知道如何滑动到最后一个 因为0 1 2 3 所以最后的position肯定为3 

就有了

@Override
	public void onPageSelected(int position) {
		if(position==3){
			//这里监听最后一个页面
			ib.setBackgroundResource(R.drawable.btnen);
			ib.setClickable(true);
			ib.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					startActivity(new Intent(GideActivty.this, MainActivity.class));
				}
			});
		}
		
	}

我们前面不让其点击生效使用了setClickable的false或者true 

然后去动态的改变图 

private void setListener() {
		pager.setOnPageChangeListener(this);
		ib.setClickable(false);
		
	}

这里面方法的setOnpagerChangListener是我们使用viewpager的时候最常用的一个监听 

但是这里面有个问题 就是 我们在滑动到最后一个界面的时候 再划回来 由于设置背景 所以改不回来了 因此 还要加上逻辑判断 

@Override
	public void onPageSelected(int position) {
		if(position==3){
			//这里监听最后一个页面
			ib.setBackgroundResource(R.drawable.btnen);
			ib.setClickable(true);
			ib.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					startActivity(new Intent(GideActivty.this, MainActivity.class));
				}
			});
		}else{
			ib.setClickable(false);
			ib.setBackgroundResource(R.drawable.btnnormal);
		}
		
	}

剩下要做的就是注释掉setListener的的setClickXXX方法即可 

效果图如下 


最后一个需求 是要第一次进入应用的时候 还记得首选项么 没错 我们就用首选项存数据 

代码如下

我们这个时候 需要建立一个splash界面 

再写一个活动

<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"
    android:background="@drawable/bg"
    tools:context=".MainActivity" >

   
  </RelativeLayout>

这里面的代码非常简单 就一张图


启动界面代码

public class SplashActvity extends Activity {
	
	private Handler mHandler =  new Handler(){
		public void handleMessage(android.os.Message msg) {
			
			if(sp.getBoolean("frist", false)){
				startAct(SplashActvity.this,MainActivity.class);
			}else{
				
				startAct(SplashActvity.this, GideActivty.class);
				sp.edit().putBoolean("frist", true).commit();
				finish();
			}
			
			
		};
		
	};
	private SharedPreferences sp;
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(R.layout.activity_sp);
		sp = this.getSharedPreferences("config", MODE_PRIVATE);
	
		sendMessage();
	}


	private void sendMessage() {
		mHandler.sendEmptyMessageDelayed(0, 2000);
		
	}


	protected void startAct(Context ct,
			Class clazz) {
		startActivity(new Intent(ct, clazz));
		
	}

}

这里面也非常简单 主要是利用了消息机制 这个我们以后会讲到 发一个消息 

然后第一次进入的时候 将数据存入首选项 否则走splash 

最后别忘了清单文件中注册 其实 这个引导界面还有一些比较有趣的特效可以完成 比如我们在滑动的时候 

小圆点是动态透明度改变的 这实际上是改变了alpha值 这些在应用里面都可以实现 以后有时间的话 我会继续进行讲解 

包括一些3D界面的引导 (听上去是不是很炫酷呢)

好了 这次先到这里 估计有点多 大家慢慢看 咱下次再见

本期代码下载

http://download.csdn.net/detail/mtgodd/8069255

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值