整体的设计步骤:
1.设置布局,大体上先设置一个Viewpager做为所有Image的容器
2.设置好Viewpager容器后,需要给Viewpager设置数据,把Image填充进去的话,就需要给Viewpager设置一个Adapter,在Adapter的instantiateItem()初始化布局方法中,把Image填充进去,只是在这当中,我们把ImageView放到了一个集合中,方便在instantiateItem()初始化布局方法中使用
4.动态设置小红点中涉及到了ViewPager的滑动事件,在这个事件里面我们先通过ImageView的视图树拿到mPointDis小红点移动距离,再通过它修改小红点的左边距,进而修改它的位置
难点:
我们怎么才能拿到小红点的移动位置呢?在onCreate方法中我们拿不到,因为这个时候布局还没有开始进行绘制,只有onCreate方法执行完毕之后才能拿到. 那拿不到的话我们在onStart方法,或者是onResume方法中是不是可以拿到呢?其实,这俩方法里面没有什么复杂的逻辑,它们很快的就会执行完毕,而我们的测量,布局,绘制却会花费很多的时间,所以很可能我们根本就拿不到数据,那到底我们应该怎么做才能拿到数据呢?
这个里面就用到了视图树,可以监听ImageView的layout执行结束的事件.在它的视图树onGlobalLayout()回调方法中得到测量的结果,什么意思呢,就是说,我先不管你到底是有多大的距离,反正我也拿不着数据,那只好等你layout布局完之后告诉我喽
布局:
android:layout_width="match_parent"
android:layout_height="match_parent" >
//实际上里面的容器是一个viewpager,去盛放我们的Image,而所有的Image是以background进行设置的.
android:layout_width="match_parent"
android:layout_height="match_parent" />
//这里我们做了一个"开始体验"的按钮,整体的布局是个相对布局,
还有一个是我们在相对布局中定义出来的浮在画出来的小灰点上的小红点
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="30dp" >
//搞一个线性布局做为容器,动态的添加小圆点,这个布局中小圆点的出现是我们自己shape出来的
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
//小红点的布局
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/shape_point_selected" />
Viewpager的适配器:
class GuideAdapter extends PagerAdapter {
@Override
public int getCount() {
return mImageIds.length;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
//初始化布局
@Override
public Object instantiateItem(ViewGroup container, int position) {
//ImageView view = new ImageView(getApplicationContext());
ImageView view = mImageViews.get(position);
container.addView(view);
return view;
}
//销毁布局
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
"开始按钮"的两个状态选择器:
btn_guide_selector:
txt_guide_selector:
shape小圆点的布局:
默认的小圆点:shape_point_normal
android:width="10dp" />
选中之后的小圆点:shape_point_selected
android:width="10dp" />
整体代码的涉及:
package com.hello.test;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Intent;
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.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import com.xxx.xxx.utils.PrefUtils;
/**
* 新手引导页
*/
public class GuideActivity extends Activity {
private ViewPager mViewPager;
private LinearLayout llContainer;
private ImageView ivRedPoint;
private Button btnStart;
//图片id集合,用一个数组把图片维护起来
private int[] mImageIds = new int[] { R.drawable.guide_1,
R.drawable.guide_2, R.drawable.guide_3 };
private ArrayList
private int mPointDis;//圆点移动距离
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);//从代码中去掉标题栏的方法, 必须在setContentView之前调用
setContentView(R.layout.activity_guide);
initViews(); //把findViewById()方法放在这个方法里面,让整个界面代码界面显得更精简
initData();
}
//初始化布局
private void initViews() {
mViewPager = (ViewPager) findViewById(R.id.vp_guide);
llContainer = (LinearLayout) findViewById(R.id.ll_container);
ivRedPoint = (ImageView) findViewById(R.id.iv_red_point);
btnStart = (Button) findViewById(R.id.btn_start);
}
//初始化数据
private void initData() {
//初始化三张图片的ImageView
mImageViews = new ArrayList
//通过for循环把int[]数组中的id设置到集合中
for (int i = 0; i < mImageIds.length; i++) {
ImageView view = new ImageView(this);
view.setBackgroundResource(mImageIds[i]);//用这个方法是希望每个图片都填充我们的屏幕
mImageViews.add(view);
//初始化小圆点
ImageView point = new ImageView(this);
//R.drawable.shape_point_normal是我们自己画出来的小圆点
point.setImageResource(R.drawable.shape_point_normal);
//初始化布局参数,设置小圆点的距离参数
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
//逻辑设置布局参数
if (i > 0) {
params.leftMargin = 10;//从第二个点开始设置左边距10px
}
point.setLayoutParams(params);//设置布局参数
llContainer.addView(point);
}
//给ViewPager设置数据的话,就需要给Viewpager设置一个Adapter
mViewPager.setAdapter(new GuideAdapter());
//小红点的动态处理事件应该存在的地方
//监听ViewPager滑动事件,更新小红点位置
mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
if (position == mImageIds.length - 1) {
//最后一个页面显示开始体验按钮
btnStart.setVisibility(View.VISIBLE);
} else {
btnStart.setVisibility(View.GONE);
}
}
//监听滑动事件
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
System.out.println("当前位置:" + position + ";偏移百分比:"
+ positionOffset);
//这里我们的小红点不用像上面小灰点一样再去new,因为它本身就是存在的,所以,直接设置它的参数就可以了
//通过修改小红点的左边距来更新小红点的位置
int leftMargin = (int) (mPointDis * positionOffset + position
* mPointDis + 0.5f);//要将当前的位置信息产生的距离加进来
//获取小红点的布局参数
RelativeLayout.LayoutParams params = (LayoutParams) ivRedPoint
.getLayoutParams();
params.leftMargin = leftMargin;
ivRedPoint.setLayoutParams(params);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
//计算圆点移动距离 = 第二个圆点的左边距-第一个圆点左边距
// mPointDis = llContainer.getChildAt(1).getLeft()
// - llContainer.getChildAt(0).getLeft();
// System.out.println("mPointDis:" + mPointDis);
// System.out.println("mPointDis1:" + llContainer.getChildAt(1).getLeft());
// System.out.println("mPointDis2:" + llContainer.getChildAt(0).getLeft());
//measure->layout->draw, 必须onCreate执行结束之后,才会开始绘制布局,走此三个方法
//监听layout执行结束的事件, 一旦结束之后, 在去获取当前的left位置
//视图树
ivRedPoint.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
//一旦视图树的layout方法调用完成, 就会回调此方法
@Override
public void onGlobalLayout() {
//布局位置已经确定,可以拿到位置信息了
mPointDis = llContainer.getChildAt(1).getLeft()
- llContainer.getChildAt(0).getLeft();
System.out.println("mPointDis:" + mPointDis);
//移除观察者
//ivRedPoint.getViewTreeObserver().removeOnGlobalLayoutListener(this);
//这是一个过时的方法
ivRedPoint.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
}
});
//开始体验按钮点击
btnStart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//在sp中记录访问过引导页的状态,在闪屏页面getBoolean来判断是否需要展现新手引导页面
PrefUtils.putBoolean(getApplicationContext(), "is_guide_show",
true);
//跳到主页面
startActivity(new Intent(getApplicationContext(),
MainActivity.class));
finish();
}
});
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onResume() {
super.onResume();
}
class GuideAdapter extends PagerAdapter {
@Override
public int getCount() {
return mImageIds.length;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
//初始化布局
@Override
public Object instantiateItem(ViewGroup container, int position) {
//下面的这种方式因为每次都会new出一个Image对象,有点浪费性能,我们放弃掉,所以我们可以提前new好它,在我们上面的initData()方法中
//ImageView view = new ImageView(getApplicationContext());
ImageView view = mImageViews.get(position);
container.addView(view);
return view;
}
//销毁布局
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
}
一个SP的工具类:
package com.xxx.xxx.utils;
import android.content.Context;
import android.content.SharedPreferences;
/**
* 专门访问和设置SharePreference的工具类, 保存和配置一些设置信息
*
* @author Kevin
*
*/
public class PrefUtils {
private static final String SHARE_PREFS_NAME = "itxxx";
public static void putBoolean(Context ctx, String key, boolean value) {
SharedPreferences pref = ctx.getSharedPreferences(SHARE_PREFS_NAME,
Context.MODE_PRIVATE);
pref.edit().putBoolean(key, value).commit();
}
public static boolean getBoolean(Context ctx, String key,
boolean defaultValue) {
SharedPreferences pref = ctx.getSharedPreferences(SHARE_PREFS_NAME,
Context.MODE_PRIVATE);
return pref.getBoolean(key, defaultValue);
}
public static void putString(Context ctx, String key, String value) {
SharedPreferences pref = ctx.getSharedPreferences(SHARE_PREFS_NAME,
Context.MODE_PRIVATE);
pref.edit().putString(key, value).commit();
}
public static String getString(Context ctx, String key, String defaultValue) {
SharedPreferences pref = ctx.getSharedPreferences(SHARE_PREFS_NAME,
Context.MODE_PRIVATE);
return pref.getString(key, defaultValue);
}
public static void putInt(Context ctx, String key, int value) {
SharedPreferences pref = ctx.getSharedPreferences(SHARE_PREFS_NAME,
Context.MODE_PRIVATE);
pref.edit().putInt(key, value).commit();
}
public static int getInt(Context ctx, String key, int defaultValue) {
SharedPreferences pref = ctx.getSharedPreferences(SHARE_PREFS_NAME,
Context.MODE_PRIVATE);
return pref.getInt(key, defaultValue);
}
}