引导页是第一次进APP才有的,他的效果是左右滑动几张图片,展现一些功能之类的,最后一张图片应该有个button,点击后计入主页面,同时在页面下部有红点
这要用到viewPager,安卓自己带有这个包,只需在布局里使用全名就能引用到
<?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/vp_guide"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
然后回activity找到他,他要把几张图展现出来就需要adapter,adapter内要4个重载方法,第一个方法需要引用图片位置,所以建一个数组存放,而后需要初始化这个图片库,需要一个arraylist
public class GuideActivity extends Activity {
ViewPager vpGuide;
//第二步(1) 导入图片后,将位置信息放到一个数组里方便后面引用
private static final int[] mImageIds = new int[] { R.drawable.guide_1,
R.drawable.guide_2, R.drawable.guide_3 };
//第三步(2) 初始化图片库,需要一个ArrayList
private ArrayList<ImageView> mImageViewList;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题
setContentView(R.layout.activity_guide);
//第一步(1) 找到vp初始化
vpGuide = (ViewPager) findViewById(R.id.vp_guide);
//第三步(1) 初始化图片以及小圆点
initViews();
//第一步(2) 设置adapter
vpGuide.setAdapter(new GuideAdapter());
}
//第三步(3) 初始化
private void initViews() {
mImageViewList = new ArrayList<ImageView>();
//第三步(4) 初始化引导页的3个页面
for (int i = 0; i < mImageIds.length; i++) {
ImageView image = new ImageView(this);
image.setBackgroundResource(mImageIds[i]);// 设置引导页背景
mImageViewList.add(image);
}
}
//第一步(3) 需要adapter填充
class GuideAdapter extends PagerAdapter {
@Override
public int getCount() {
//第二步(2) 位置信息 或者是list的size也可以
return mImageIds.length;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
//第三步(6) 表明传回的object就是这个view,直接return true也可
return arg0 == arg1;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
//第三步(5) 初始化好后,根据位置信息来填充
container.addView(mImageViewList.get(position));
return mImageViewList.get(position);//super.instantiateItem(container, position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
//第三步(7) 划出去的要手动销毁 ((View) object)也可以
container.removeView(mImageViewList.get(position));
}
}
}
再来实现下面的灰点和红点
这两类点都在整体的布局上,所以整体的布局是relativeLayout;而后这个红点也是相对于灰点位移而来,所以这里也是一个relativeLayout。
两类点都是在drawable文件夹下使用shape节点来实现,oval表示圆,solid表示实心
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="#f00" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="@android:color/darker_gray" />
</shape>
灰点当成LinearLayout的view,随着滑动页面的增加而增加,无需定义死个数,给个ID直接在代码里直接初始化就好;而红点当成是一个imageview,需要跟随滑动,要在Viewpager的一个重载函数里实现。
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp" >
<LinearLayout
android:id="@+id/ll_point_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
</LinearLayout>
<View
android:id="@+id/view_red_point"
android:layout_width="10dp"
android:layout_height="10dp"
android:background="@drawable/shape_point_red" />
</RelativeLayout>
去activity里找到这些点
//第四步(1) 圆点的实现
private LinearLayout llPointGroup;// 灰点
private int mPointWidth;// 圆点间的距离
private View viewRedPoint;// 小红点
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题
setContentView(R.layout.activity_guide);
//第四步(2) 两类圆点
llPointGroup = (LinearLayout) findViewById(R.id.ll_point_group);
viewRedPoint = findViewById(R.id.view_red_point);
小灰点的初始化,小灰点本身就是一个布局,他的个数随着滑动页面的增加而增加,小灰点之间的距离需要通过代码设置属性
//第四步(3) 初始化小灰点 这里根据我们滑动图片的张数来增加小灰点的个数,无需手动定义
for (int i = 0; i < mImageIds.length; i++) {
//1.imageView亦可
View point = new View(this);
//2.根据前面的XML定义,设置引导页默认圆点
point.setBackgroundResource(R.drawable.shape_point_gray);
//4.给灰点这个布局设置属性,宽高
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
10, 10);
if (i > 0) {
params.leftMargin = 10;//5.设置圆点间隔,第一个点不需要
}
point.setLayoutParams(params);// 设置圆点的大小
llPointGroup.addView(point);//3.将圆点添加给线性布局
}
接着来实现红点,viewpager里面的OnPageChangeListener
//第五步(1),需要一个OnPageChangeListener来实现红点的移动
vpGuide.setOnPageChangeListener(new GuidePageListener());
//第五步(2) 实现OnPageChangeListener,三个callback
class GuidePageListener implements OnPageChangeListener {
@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 arg0) {
// TODO Auto-generated method stub
}
}
需要关联源码
右击工程名-properties-Libraies-Java buildpath-将第三个包remove-在add进来
这时候再去点击某个类,会让你添加源码
Attach folder 选择sdk/extras/android/support/v4
删除原来的重载方法,重新加入,都有了参数,OK
注意,要打钩
第一个方法,onPageScrolled,当view滑动时被调用
第一个参数 Position 表示当前处于哪个view
第二个参数 positionOffset 表示当前滑出的比例
第三个参数 表示划出的像素
从一个灰点的位置移到另一个灰点,移动的距离应该是2倍的灰点键距离,也就是20.,不过这里用代码实现
其中要获取两个小灰点间的距离,如图
小灰点的这个布局在实现过程中可以获取到相关属性,所以要在初始化中去获取这个距离
/*
* 第五步(3) 红点的移动需要获取小灰点间的距离
* 故而需要在初始化中监听灰点的构建,addOnGlobalLayoutListener
* view的过程:measure,layout,draw
*/
llPointGroup.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
//当layout执行结束后回调此方法
@Override
public void onGlobalLayout() {
System.out.println("layout 结束");
llPointGroup.getViewTreeObserver().removeGlobalOnLayoutListener(this);
mPointWidth = llPointGroup.getChildAt(1).getLeft()
- llPointGroup.getChildAt(0).getLeft();
System.out.println("圆点距离:" + mPointWidth);
}
});
再来看小红点移动的距离:
两点间的距离 灰点间距离 乘以 view移动的百分比
跨点时,灰点距离 乘以 灰点的位置信息
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
System.out.println("当前位置:" + position + ";百分比:" + positionOffset
+ ";移动距离:" + positionOffsetPixels);
//第五步(4) 由灰点间距离和view移动的百分比来测算红点应该移动的距离
int len = (int) (mPointWidth * positionOffset) + position
* mPointWidth;
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) viewRedPoint
.getLayoutParams();// 获取当前红点的布局参数
params.leftMargin = len;// 设置左边距,相对于父控件RelativeLayout来说的
viewRedPoint.setLayoutParams(params);// 重新给小红点设置布局参数
}
OK,实现在最后一个页面点击button跳转到主页面
布局,这里按键后颜色和背景都改变,需要定义selector
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/button_red_pressed" android:state_pressed="true"/>
<item android:drawable="@drawable/button_red_normal"/>
</selector>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="@android:color/black"/>
<item android:color="@android:color/white"/>
</selector>
<pre name="code" class="html"><Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="60dp"
android:background="@drawable/btn_guide_selector"
android:padding="5dp"
android:text="开始体验"
android:visibility="invisible"
android:textColor="@drawable/btn_guide_text_selector"/>
这个按钮找到后,在onPageSelected内,只有最后一面显示这个button,别的都隐藏
@Override
public void onPageSelected(int position) {
// 第六步(2) button点击跳转
if (position == mImageIds.length - 1) {// 最后一个页面
btnStart.setVisibility(View.VISIBLE);// 显示开始体验的按钮
} else {
btnStart.setVisibility(View.INVISIBLE);
}
}
设置响应,并改变sp
//第六步(2) 找到button
btnStart = (Button) findViewById(R.id.btn_start);
//第六步(4) 跳转,并设置boolean,以后不再进入引导页
btnStart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 更新sp, 表示已经展示了新手引导
PrefUtils.setBoolean(GuideActivity.this,
"is_user_guide_showed", true);
// 跳转主页面
startActivity(new Intent(GuideActivity.this, MainActivity.class));
finish();//免得用户后退又回来了,销毁他
}
});
OK~