App引导界面,可以这么玩
什么是ViewPager,刚一听到这个词,我们可能感觉很奇怪,但是我相信我们大部分人都曾见到过这些界面的。其实它就是我们在安装好一个app之后第一次使用时的那些引导界面的效果。这就是通过ViewPager来完成滴。今天,就让我们一起走进ViewPager的世界吧。
理论基础
- 其实说是理论基础,也只不过是一些小知识点罢了,所以不要紧张咯。ViewPager在ADT开发时使用到了android.support.v4.view.ViewPager控件,我们需要知道这点就可以了。
- 我们可以把ViewPager看作是一个ListView样式的控件,然后按照对待ListView的眼光来看待ViewPager,就会很轻松了。
- ListView需要一个适配器,而ViewPager同样也是如此;ListView需要注册Item的事件侦听,ViewPager同样如此。至于底层的细节我们稍后再说。
了解了上面的这些,相信我们心中都有了一个大致的了解了吧。那我们就正式开始咯。
ViewPager怎么使用?
首先我们需要在XML文件中进行声明,注意我们引用的是android.support.v4.view.ViewPager控件哦,如下:
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00000000"
>
</android.support.v4.view.ViewPager>
然后是在Java代码中findViewById一下,免得出现NullPointerExcetion.
了解到了ViewPager是一个View的容器,那么我们当然要有View才行了,所以我们在layout文件夹下创建几个用于呈现的view。由于比较相似,我这里就仅仅写出一个XML文件吧。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/guide_3" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<Button
android:id="@+id/start_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="进入" />
</LinearLayout>
<!--由于这是第三个布局,也就是引导的最后一个,我们提供了一个进入主界面的按钮-->
</RelativeLayout>
现在万事俱备,只欠东风了。所以我们就需要创建一个适配器了,这里需要注意的是适配器要继承自PagerAdapter
,具体的代码如下:
package com.mark.viewpagerdemo;
import java.util.List;
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
/**
* 这个类的作用就是对于ViewPager的Activity(View)的切换的
* 时候需要的一个适配器的作用,其实ViewPager的原理就可以看作是一个ListView就行了
* @author lhdn
*
*/
public class ViewPageAdapter extends PagerAdapter{
//list是为了存储容器中的view,context的作用就是上下文
private List<View> views;
private Context context;
public ViewPageAdapter(List<View > mViews , Context mContext) {
this.context = mContext;
this.views = mViews;
}
/**
* 将不需要呈现的view及时的销毁
*/
@Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView(views.get(position));
}
/**
* 该方法的作用类似于ListViewAdapter的那个getView的作用
*/
@Override
public Object instantiateItem(View container, int position) {
((ViewPager) container).addView(views.get(position));
return views.get(position);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return views.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
// 判断当前获得的view是不是我们想要得到的view
return (arg0 == arg1);
}
}
其中方法:
@Override
public Object instantiateItem(View container, int position) {
((ViewPager) container).addView(views.get(position));
return views.get(position);
}
就好比我们的ListViewAdapter的getView方法。功能就是获得一个view,即可。
如果不需要在图片上添加效果的话,这样其实就已经是搞定了,我们可以测试一下效果,发现这个小案例已经是可行的了。
ViewPager添加一些效果
所谓添加效果,就是添加上几个小圆点,比如我们滑动View的时候下面会出现的一些小亮点和小暗点等,其目的是为了显示我们确实滑动了ViewPager,也为了美观嘛。那么我们要怎么实现呢?答案就是使用ImageView就可以了,但是切记只需要在ViewPager所在的界面进行添加就可以了,而不需要为其他的XML文件进行添加。然后我们在ViewPager的OnPageChangeListener处理事件中进行相关的设置就可以了。如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00000000"
>
</android.support.v4.view.ViewPager>
<LinearLayout
android:id="@+id/ll"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<ImageView
android:id="@+id/iv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/login_point_selected" />
<ImageView
android:id="@+id/iv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/login_point" />
<ImageView
android:id="@+id/iv3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/login_point" />
</LinearLayout>
</RelativeLayout>
package com.mark.viewpagerdemo;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class Guide extends Activity implements OnPageChangeListener {
private ViewPager vp;
// 因为viewpager的使用要街注意一个适配器,所以要创建一个适配器的对象
private ViewPageAdapter vpAdapter;
// 创建一些视图View,用于放置到我们的ViewPager容器中
private List<View> views;
// 存储图像的小点
private ImageView[] dots;
// 图片小点的ID值
int[] ids = new int[] { R.id.iv1, R.id.iv2, R.id.iv3 };
private Button enter ;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.guide);
initViews();
initDots();
}
/**
* 初始化ViewPager机器内部的view视图
*/
public void initViews() {
views = new ArrayList<View>();
LayoutInflater inflater = LayoutInflater.from(this);
// 向ViewPager中添加view
views.add(inflater.inflate(R.layout.one, null));
views.add(inflater.inflate(R.layout.two, null));
views.add(inflater.inflate(R.layout.three, null));
// 为进入主界面的按钮申请资源,由于button的值在第三个view中,而这里是Guide的
// 所以,要先得到第三个view之后,才能使用findViewById()方法
enter = (Button) views.get(2).findViewById(R.id.start_btn);
enter.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent(Guide.this, MainActivity.class);
startActivity(intent);
finish();
}
});
// 创建ViewPager以及添加适配器
vp = (ViewPager) findViewById(R.id.viewpager);
vpAdapter = new ViewPageAdapter(views, this);
vp.setAdapter(vpAdapter);
// 为ViewPager 注册监听事件
vp.setOnPageChangeListener(this);
}
/**
* 初始化需要的点的资源
*/
public void initDots() {
dots = new ImageView[views.size()];
for (int i = 0; i < dots.length; i++) {
dots[i] = (ImageView) findViewById(ids[i]);
}
}
// ///////////////////////////////////////////onViewPagerChangeListener接口的方法开始
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int arg0) {
for (int i = 0; i < ids.length; i++) {
if (arg0 == i) {
dots[i].setImageResource(R.drawable.login_point_selected);
} else {
dots[i].setImageResource(R.drawable.login_point);
}
}
}
// ///////////////////////////////////////////onViewPagerChangeListener接口方法结束
}
测试后发现,成了!这样就已经是完整的实现了我们需要的功能了。
深入的思考
虽然我们已经完成了ViewPager的使用了,但是仔细的想一想,我们真的完成了吗?
其实并不是的,因为这样的话,我们每一次打开这个APP,就会出现一个引导界面,这样是不符合事实的,因为我们并不希望每一次都看到这个引导界面,所以我们现在要完成的就是如何实现只在第一次的时候才显示引导界面。
实现的思路:使用一个变量,放置到文件的存储中,每次打开APP的时候检验这个值,如果是第一次使用,就跳转到引导界面,如果不是,就跳转到主界面,所以我们现在就要实现这个中间层的界面了。实现的效果就是打开APP的时候显示这个中间层的界面,然后在跳转到其他的引导界面或者主界面。
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:orientation="vertical" >
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/welcome_android"
/>
</LinearLayout>
package com.mark.viewpagerdemo;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.os.Handler;
public class Welcome extends Activity {
//设置一个延迟时间,为界面的跳转来争取时间
private static final int TIME = 2000;
private static final int GO_HOME = 1000;
private static final int GO_GUIDE = 1001;
//设置一个参数,实现只为第一次进入的时候显示guide界面,这个参数要存储进本地的一个参数,
//见下面的initValue方法
private boolean isFirstIn = true;
private void initValue(){
SharedPreferences sp = getSharedPreferences("ViewPagerDemo",MODE_PRIVATE);
isFirstIn = sp.getBoolean("isFirstIn", true);
if(isFirstIn) {
mHandler.sendEmptyMessageDelayed(GO_GUIDE,TIME);
Editor editor = sp.edit();
editor.putBoolean("isFirstIn", false);
editor.commit();
}else{
mHandler.sendEmptyMessageDelayed(GO_HOME,TIME);
}
}
//等待时间不能在主进程,所以使用handler
private Handler mHandler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch(msg.what){
case GO_HOME:
goHome();
break;
case GO_GUIDE:
goGuide();
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome);
initValue();
}
private void goHome(){
Intent i = new Intent(Welcome.this,MainActivity.class);
startActivity(i);
finish();
}
private void goGuide(){
Intent i = new Intent(Welcome.this,Guide.class);
startActivity(i);
finish();
}
}
Welcome.java 深入剖析:
由于我们设置了在欢迎界面的等待时间,所以就最好是使用handler来实现界面的更新,这样符合“在主线程更新UI”原则。于是使用了SharedPreferences来实现了值得记录。
优化思路,其实我觉得在initValue方法中初始化的方式也不是特别的好,如果在静态代码中进行的话,效果会更好。
handler的使用是至关重要的一个知识点,我们要记得在主线程中进行UI界面的更新,所以要在主线程中对其他线程传递过来的,msg.what进行处理。
测试结果
点击运行完程序之后,我们会发现只有在第一次使用APP的时候才会出现引导界面,一旦我们进入过了主界面,引导界面就不会再出现了。除非你重新安装了,(^__^) 嘻嘻……
知识点回顾
这个小项目的主要的流程是这样的,
* 先是了解了什么是ViewPager,
* 然后学会了ViewPagerAdapter适配器的使用,
* 再然后就是对PageChange事件的处理
* 学会了如何使用handler配合UI的更新
* 再就是添加了常量值的配合实现了“一次性计划”
* 接下来就真的完成了,虽然界面不好看,但是核心的思想却是都在这里了。
项目源代码下载地址
App引导界面,可以这么玩的更多相关文章
- App 引导界面
App 引导界面 1.前言 最近在学习实现App的引导界面,本篇文章对设计流程及需要注意的地方做一个浅显的总结. 附上项目链接,供和我水平类似的初学者参考——http://files.cnblogs. ...
- 使用UIPageControl UIScrollView制作APP引导界面
1. 新建两个视图控制器类(继承自UIViewController), 在AppDelegate.m中指定根视图控制器 #import "AppDelegate.h" #impor ...
- android——利用SharedPreference做引导界面
很久以前就接触过sharedPreference这个android中的存储介质.但是一直没有实际使用过,今天在看之前做的“民用机型大全”的app时,突然想到可以使用sharedPreference类来 ...
- 【Android UI设计与开发】第05期:引导界面(五)实现应用程序只启动一次引导界面
[Android UI设计与开发]第05期:引导界面(五)实现应用程序只启动一次引导界面 jingqing 发表于 2013-7-11 14:42:02 浏览(229501) 这篇文章算是对整个引导界 ...
- Android UI开发第四十一篇——墨迹天气3.0引导界面及动画实现
周末升级了墨迹天气,看着引导界面做的不错,模仿一下,可能与原作者的代码实现不一样,但是实现的效果还是差不多的.先分享一篇以前的文章,android动画的基础知识,<Android UI开发第十二 ...
- 【Android UI设计与开发】3.引导界面(三)实现应用程序只启动一次引导界面
大部分的引导界面基本上都是千篇一律的,只要熟练掌握了一个,基本上也就没什么好说的了,要想实现应用程序只启动一次引导界面这样的效果,只要使用SharedPreferences类,就会让程序变的非常简单, ...
- 【Android】首次进入应用时加载引导界面
参考文章: [1]http://blog.csdn.net/wsscy2004/article/details/7611529 [2]http://www.androidlearner.net/and ...
- SharedPreference 存储小量数据,一般首次启动显示引导界面就用这个。
写://添加一个SharedPreference并传入数据SharedPreference sharedPreferences = getSharedPreferences("share_d ...
- 转-ViewPager组件(仿微信引导界面)
http://www.cnblogs.com/lichenwei/p/3970053.html 这2天事情比较多,都没时间更新博客,趁周末,继续继续~ 今天来讲个比较新潮的组件——ViewPager ...
随机推荐
- hdu 2896 病毒侵袭 AC自动机(查找包含哪些子串)
病毒侵袭 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- Mac上安装brew 包管理工具
Mac 上的包管理工具对于开发者来说是一件非常方便的工具,能够有效的对包进行管理. 所以这篇博客就来简单的讲一下brew 的安装和一些基础命令. brew 全称叫做Homebrew . 1. 首先来说 ...
- 数组查找算法的C语言 实现-----线性查找和二分查找
线性查找 Linear Search 用户输入学生学号的成绩 二分查找 Binary Search 要求数据表是已经排好序的 程序存在小的瑕疵
- pm2进阶使用
启用集群模式 只需要在启动应用时带上i参数 pm2 start app.js -i max max:意味着PM2将自动检测可用的CPU数量和运行多个进程可以在负载均衡模式(但是不推荐使用) 或者使用j ...
- Lintcode391 Number of Airplanes in the Sky solution 题解
[题目描述] Given an interval list which are flying and landing time of the flight. How many airplanes ar ...
- (一)python基础知识
Python:解释型语言(一边翻译一边运行)注释:单行注释(#).多行注释(ctrl+/):''' '''和""" """ (python2 ...
- c++ 文件操作详解
C++ 通过以下几个类支持文件的输入输出: ofstream: 写操作(输出)的文件类 (由ostream引申而来) ifstream: 读操作(输入)的文件类(由istream引申而来) fstre ...
- 保留键的情况下取字典中最大的值(max\zip函数的联合使用)
在我们平常想要获取字典中value最大或者最小的值的时候,常常使用如下函数: testDict = {"age1":18,"age2":20,"age ...
- 初始化mysql数据库——Activiti BPM
package com.initialize; import org.activiti.engine.ProcessEngine; import org.activiti.engine.Process ...
- 使用FFMPEG在windows平台下推rtmp流
使用FFMPEG在windows平台下推rtmp流 工作中习惯在Linux下面使用FFmpeg模拟推rtmp流,无奈家中的电脑都是windows系统,需要利用家中的带宽来测试流媒体服务器的性能.所以研 ...