一 引导页
效果图:
1.1 什么是引导页?
在网络上做了一些查询,没有找到引导页的官方或权威定义,决定从其字面意思来进行推论。所谓引导页,就是引导用户学习app用法或了解app作用的页面,其核心在于“引导”二字。在此情况下,若一个号称引导页的东西不能达到让用户学习app的用法,或了解app相关,都不能使真正意义上的引导页。
1.2 为什么要用引导页?
到底为什么多数app都会在很多情况下增加引导页呢?个人认为原因在于以下几点:
- 受传统pc时代软件说明书的影响。pc时代的一个软件,用户往往不知道如何操作,甚至需要上专门的课程学习某个软件才行,比如office系列。因此,每个软件一旦销售必然配备使用说明书,以帮助用户学习。但是,在移动互联网时代,对于轻量级的app使用说明书太重了,所以使用了引导页这种轻量级的方式。
- app设计者假设用户会希望了解这个app到底是个什么东西?能干什么?怎么用?所以要做引导页来回答用户内心的这些问题。
- app设计者看到别人有,没有多想,觉得自己的app也应该做一个。
然而,现实中的情况是什么呢?
- 在这个注重极致用户体验的时代,绝大多数app的设计已经可以做到不证自明的阶段。用户一看就知道这玩意儿应该怎么用,能用来干什么。
- 即使用户对某个app没有任何认知,在下载这个app之前也肯定会有一些前置了解来帮助自己决定是否有必要下载(产品狗除外,什么app都会划拉下来看看),或者道听途说,或者朋友推荐等等。因此,引导页能够告诉用户的多数情况下是他已经知道的。
- 即使还需要深入了解的app(甚至手机系统这么复杂的玩意儿),多数的用户还是会采取自我探索的方式来学习如何使用。而这种学习方式对于成长在互联网时代的90、00、10后更是如此。(我四岁的侄女不识字照样可以用手机拍照、看动画片)。
- 用户打开app的目的是使用其功能来完成任务,往往不希望有任何障碍。因此,真正有耐心看完引导页的用户很少,多数会直接快速滑动跳过。即使引导页做得再好。
- 很多公司其实已经注意到了这种情况,所以他们在引导页上添加了“跳过”按钮,来防止用户对翻好几页引导页而反感。
因此,从某种意义上来说,引导页的存在其实是一个大家觉得存在没什么不对,但是却又没太多人用的这么一个东西。 那么,是不是不需要做引导页了呢?我想说的是:对,不需要做引导页了。除非:
- 你的app是一个全新概念的app,是市面上没有人有过的玩法。即使用户能够从各种途径了解到相关信息,但也无法完全理解你所想要传达的信息。你有不说就死的理由。此种情况下,你可以做引导页,也许能够让部分用户加深对app的了解。
- 你的app增加了非常大块的功能,大到可能改变整个app的使用场景,值得你重点强调。就像发布一个全新的app一样。
- 你的app新增加了非常重要的功能,但又无法在界面上重点展示(离线下载的控制),非常有必要向你的用户强调。
- 你的app使用了别人不曾用过的或用户难以想到的操作方式,同时又对使用app有重大影响,必须介绍。
1.3 效果图
1.4 安卓的实现形式
Android的APP应用中最常用的 APP启动引导页 ,常见的4种引导项目方式:
- splash
- viewpage
- viewflipper
- scrollview
1.5 开源组件
1.6 素材来源
1.7 注意点
- 引导页一般是在用户第一次进入app时给用户的友好提示,包括介绍app的基本功能,最近更新的功能等等。因此只会初始化一次。
- 目前市场上的app的引导页大部分都是采用ViewPager滑动的方式实现,每一个页面采用图片或者素材加图片的方式填充。
二 ViewPager实现引导页
2.1 ViewPage的介绍
- ViewPager是v4包中的一个类。
- ViewPager继承自ViewGroup,其实是一个容器。
- ViewPager类似于ListView,也有自己的适配器,里面用来填充数据页面。
- ViewPager一般和Fragment一起使用,它更方面的管理页面中Fragment的生命周期。
2.2 基本使用
- 编写一个自定义Adapter继承PagerAdapter
- 实现器基本方法
int getCount():返回显示多少个页面 boolean isViewFromObject(View view, Object object):判断初始化返回的Object是不是一个View对象 Object instantiateItem(ViewGroup container, int position):初始化显示的条目对象 void destroyItem(ViewGroup container, int position, Object object):销毁条目对象
2.3 基本开发
- 素材来自网络,侵权什么的请及时告知,谢谢。
- 效果图:
2.3.1 首页布局编写
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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">
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/skip_home"
android:textColor="@color/black"
android:gravity="center"
android:layout_alignParentEnd="true"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:background="@drawable/loading"
android:layout_width="40dp"
android:textSize="12sp"
android:layout_height="40dp"
android:text="@string/skip_name"/>
<LinearLayout
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_margin="30dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/imageTwo"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/imageThree"
android:layout_marginRight="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
2.3.2 设配器编写
package com.shu.Adapter;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import java.util.List;
public class GuideViewPagerAdapter extends PagerAdapter {
private List<View> views;
public GuideViewPagerAdapter(List<View> views) {
super();
this.views = views;
}
@Override
public int getCount() {
if (views != null) {
return views.size();
}
return 0;
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == (object);
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView(views.get(position));
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
(container).addView(views.get(position), 0);
return views.get(position);
}
}
2.3.3 引导页面编写
loading_view1.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="@mipmap/loading_03"
android:gravity="center|bottom"
android:orientation="vertical">
<Button
android:id="@+id/start_home"
android:background="@drawable/btn_go"
android:textColor="@color/white"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginBottom="90dp"
android:text="@string/home_name" />
</LinearLayout>
2.3.4 小圆圈样式编写
未选中:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="#03A9F4"/>
<size
android:width="5dp"
android:height="5dp"/>
</shape>
选中:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="#040404"/>
<size
android:width="5dp"
android:height="5dp"/>
</shape>
2.3.5 主要代码逻辑编写
package com.shu.Activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.shu.Adapter.GuideViewPagerAdapter;
import com.shu.Common.SysConfig;
import com.shu.R;
import java.util.ArrayList;
import java.util.List;
public class LoadingActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener, View.OnClickListener {
private ViewPager viewpager;
private GuideViewPagerAdapter adapter;
private List<View> views;
private int[] pics = {R.layout.guid_view1, R.layout.guid_view2, R.layout.guid_view3};
private ImageView[] imageViews;
private ImageView imageOne, imageTwo, imageThree;
private Button button_01;
private TextView textView_01;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loading);
SharedPreferences preferences = this.getSharedPreferences( "data_init", Context.MODE_PRIVATE );
if(preferences.getString("flag", "").equals("")){
viewpager = this.findViewById(R.id.viewpager);
imageOne = this.findViewById(R.id.imageOne);
imageTwo = this.findViewById(R.id.imageTwo);
imageThree = this.findViewById(R.id.imageThree);
initView();
textView_01=findViewById(R.id.skip_home);
textView_01.setOnClickListener(this);
}
else {
GoToLogin();
}
}
private void initView() {
if (views == null) {
views = new ArrayList<>();
}
if (imageViews == null) {
imageViews = new ImageView[3];
}
imageViews[0] = imageOne;
imageViews[1] = imageTwo;
imageViews[2] = imageThree;
setPointSelect(true, 0);
for (int i = 0; i < pics.length; i++) {
View view = LayoutInflater.from(this).inflate(pics[i], null);
views.add(view);
}
adapter = new GuideViewPagerAdapter(views);
viewpager.setAdapter(adapter);
viewpager.addOnPageChangeListener(this);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
setPointSelect(false, position);
if(position==2){
button_01=findViewById(R.id.start_home);
button_01.setOnClickListener(this);
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
private void setPointSelect(boolean state, int position) {
for (int i = 0; i < imageViews.length; i++) {
imageViews[i].setBackgroundResource(R.drawable.unselect);
}
if (state) {
imageViews[0].setBackgroundResource(R.drawable.select);
} else {
imageViews[position].setBackgroundResource(R.drawable.select);
}
}
@Override
public void onClick(View v) {
if(v.getId() == R.id.skip_home){
@SuppressLint("CommitPrefEdits")
SharedPreferences.Editor editor=getSharedPreferences("data_init",MODE_PRIVATE).edit();
editor.putString("flag","qwaszx123@A");
editor.apply();
GoToLogin();
}
if(v.getId()==R.id.start_home){
@SuppressLint("CommitPrefEdits")
SharedPreferences.Editor editor=getSharedPreferences("data_init",MODE_PRIVATE).edit();
editor.putString("flag","qwaszx123@A");
editor.apply();
GoToLogin();
}
}
public void GoToLogin(){
Intent intent = new Intent(LoadingActivity.this, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
overridePendingTransition(android.R.anim.fade_in,android.R.anim.fade_out);
}
}
效果图: 到此我们的代码就编写完成了。 源码地址:https://github.com/Eason-shu/Android-Demo 喜欢或对你有用,请帮我点个star,谢谢,其余实现方式后续更新。。。。。。
|