Onboarding screens are a popular way of introducing the app to the user. Although it will last only a few seconds, it is important because the story of the user dealing with your app begins from the first impression through the decision on trying to the actual interaction.
You will find many libraries for onboarding screens. But when u can create an awesome, sleek onboarding screen of a great standard and quality like some of the most popular apps, easily using just a recyclerview, it’s definitely the better way to go.
Layout
Okay, assuming you have created a new project on Android Studio, let’s begin by creating the layout.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/container" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/bottomlayout" android:orientation="vertical" android:layout_alignParentBottom="true" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:id="@+id/btnsignup" android:textColor="@android:color/white" android:text="GET STARTED" android:layout_marginLeft="32dp" android:layout_marginRight="32dp" android:padding="12dp" android:background="@drawable/btn_bg_gradient" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btnlogin" android:textColor="@color/colorPrimary" android:text="Got an account? SIGN IN" android:padding="12dp" android:layout_marginBottom="32dp" android:background="@null" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> <RelativeLayout android:layout_above="@id/bottomlayout" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v7.widget.RecyclerView> </RelativeLayout> </RelativeLayout>
Optional: Notice the “GET STARTED” button, you can use any background, or remove the attribute for default style. But if you would like the same effect as shown in the picture, add this file to drawable folder.
btn_bg_gradient.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <gradient android:angle="0" android:startColor="#2ECAD5" android:endColor="#2B95CE"/> <corners android:radius="45dp"> </corners> </shape>
That’s all the work for layout. Now let’s move to Java.
RecyclerView: scroll, paging, & indicators
Initialise the RecyclerView in the activity’s java code.
recyclerView = findViewById(R.id.recyclerView);
And we add a layout manager, which decides the direction of scroll for the RecyclerView. We need horizontal scroll.
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
Now the recyclerview will scroll horizontally, but that’s not all. We also need it to snap to each page/item. So we use PagerSnapHelper class provided by Android.
PagerSnapHelper pagerSnapHelper = new PagerSnapHelper(); pagerSnapHelper.attachToRecyclerView(recyclerView);
We are done with the scroll and paging, now we need to add the indicator dots as item decoration.
Create a new class named CirclePagerIndicatorDecoration.java
public class CirclePagerIndicatorDecoration extends RecyclerView.ItemDecoration { private int colorActive = 0xDE000000; private int colorInactive = 0x33000000; private static final float DP = Resources.getSystem().getDisplayMetrics().density; private final int mIndicatorHeight = (int) (DP * 16); private final float mIndicatorStrokeWidth = DP * 4; private final float mIndicatorItemLength = DP * 4; private final float mIndicatorItemPadding = DP * 8; private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator(); private final Paint mPaint = new Paint(); public CirclePagerIndicatorDecoration() { mPaint.setStrokeWidth(mIndicatorStrokeWidth); mPaint.setStyle(Paint.Style.STROKE); mPaint.setAntiAlias(true); } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDrawOver(c, parent, state); int itemCount = parent.getAdapter().getItemCount(); // center horizontally, calculate width and subtract half from center float totalLength = mIndicatorItemLength * itemCount; float paddingBetweenItems = Math.max(0, itemCount - 1) * mIndicatorItemPadding; float indicatorTotalWidth = totalLength + paddingBetweenItems; float indicatorStartX = (parent.getWidth() - indicatorTotalWidth) / 2F; // center vertically in the allotted space float indicatorPosY = parent.getHeight() - mIndicatorHeight * 2F; drawInactiveIndicators(c, indicatorStartX, indicatorPosY, itemCount); // find active page (which should be highlighted) LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager(); int activePosition = layoutManager.findFirstVisibleItemPosition(); if (activePosition == RecyclerView.NO_POSITION) { return; } // find offset of active page (if the user is scrolling) final View activeChild = layoutManager.findViewByPosition(activePosition); int left = activeChild.getLeft(); int width = activeChild.getWidth(); int right = activeChild.getRight(); // on swipe the active item will be positioned from [-width, 0] // interpolate offset for smooth animation float progress = mInterpolator.getInterpolation(left * -1 / (float) width); drawHighlights(c, indicatorStartX, indicatorPosY, activePosition, progress); } private void drawInactiveIndicators(Canvas c, float indicatorStartX, float indicatorPosY, int itemCount) { mPaint.setColor(colorInactive); // width of item indicator including padding final float itemWidth = mIndicatorItemLength + mIndicatorItemPadding; float start = indicatorStartX; for (int i = 0; i < itemCount; i++) { c.drawCircle(start, indicatorPosY, mIndicatorItemLength / 2F, mPaint); start += itemWidth; } } private void drawHighlights(Canvas c, float indicatorStartX, float indicatorPosY, int highlightPosition, float progress) { mPaint.setColor(colorActive); // width of item indicator including padding final float itemWidth = mIndicatorItemLength + mIndicatorItemPadding; if (progress == 0F) { // no swipe, draw a normal indicator float highlightStart = indicatorStartX + itemWidth * highlightPosition; c.drawCircle(highlightStart, indicatorPosY, mIndicatorItemLength / 2F, mPaint); } else { float highlightStart = indicatorStartX + itemWidth * highlightPosition; // calculate partial highlight float partialLength = mIndicatorItemLength * progress + mIndicatorItemPadding*progress; c.drawCircle(highlightStart + partialLength, indicatorPosY, mIndicatorItemLength / 2F, mPaint); } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); outRect.bottom = mIndicatorHeight; } }
Now back in MainActivity.java, add this to our RecyclerView
recyclerView.addItemDecoration(new CirclePagerIndicatorDecoration());
We are done with the configuration of the RecyclerView.
Adapter
The last step is to add items and an adapter.
Create the item XML layout.
view_item_intro.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"> <LinearLayout android:orientation="vertical" android:layout_marginLeft="32dp" android:layout_marginRight="32dp" android:layout_gravity="center_vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/imgview" android:layout_gravity="center_horizontal" android:adjustViewBounds="true" android:layout_width="180dp" android:layout_height="180dp" /> <TextView android:layout_marginTop="32dp" android:layout_marginBottom="8dp" android:textStyle="bold" android:textSize="20sp" android:textColor="@android:color/black" android:textAllCaps="true" android:gravity="center" android:id="@+id/txttitle" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:gravity="center" android:textSize="18sp" android:id="@+id/txtdesc" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> </LinearLayout>
Create a simple POJO for our item.
MySimpleObj.java
public class MySimpleObj { private String title; private String desc; private int pic; public MySimpleObj(String title, String desc, int pic) { this.title = title; this.desc = desc; this.pic = pic; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getPic() { return pic; } public void setPic(int pic) { this.pic = pic; } }
Now create the adapter class.
IntroAdapter.java
public class IntroAdapter extends RecyclerView.Adapter<IntroAdapter.CustomViewHolder> { private List<String> items; private Context context; public IntroAdapter(Context context, List list) { this.items = list; this.context = context; } @Override public IntroAdapter.CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.view_item_intro, viewGroup,false); IntroAdapter.CustomViewHolder viewHolder = new IntroAdapter.CustomViewHolder(view); return viewHolder; } @Override public void onBindViewHolder(IntroAdapter.CustomViewHolder holder, int i) { final MySimpleObj result = items.get(i); holder.imgview.setImageResource(result.getPic()); holder.txttitle.setText(result.getTitle()); holder.txtdesc.setText(result.getDesc()); } @Override public int getItemCount() { return items.size(); } class CustomViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ protected ImageView imgview; protected TextView txttitle,txtdesc; public CustomViewHolder(View view) { super(view); this.imgview = view.findViewById(R.id.imgview); this.txtdesc = view.findViewById(R.id.txtdesc); this.txttitle = view.findViewById(R.id.txttitle); } } }
Finally, set the items!
ArrayList<MySimpleObj> items = new ArrayList<>(); items.add(new MySimpleObj("FAST DELIVERY","Lorem ipsum dolor sit amet, consectetur adipiscing elit.",R.drawable.intro1)); items.add(new MySimpleObj("EXCITING OFFERS","Lorem ipsum dolor sit amet, consectetur adipiscing elit",R.drawable.intro4)); items.add(new MySimpleObj("SECURE PAYMENT","Lorem ipsum dolor sit amet, consectetur adipiscing elit",R.drawable.intro5)); IntroAdapter adapter = new IntroAdapter(this,items); recyclerView.setAdapter(adapter);
The complete code of the activity should look like this:
MainActivity.java
public class MainActivity extends AppCompatActivity { RecyclerView recyclerView; Button btnlogin,btnsignup; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.act_intro); recyclerView = findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); PagerSnapHelper pagerSnapHelper = new PagerSnapHelper(); pagerSnapHelper.attachToRecyclerView(recyclerView); recyclerView.addItemDecoration(new CirclePagerIndicatorDecoration()); ArrayList<MySimpleObj> items = new ArrayList<>(); items.add(new MySimpleObj("FAST DELIVERY","Lorem ipsum dolor sit amet, consectetur adipiscing elit.",R.drawable.intro1)); items.add(new MySimpleObj("EXCITING OFFERS","Lorem ipsum dolor sit amet, consectetur adipiscing elit",R.drawable.intro4)); items.add(new MySimpleObj("SECURE PAYMENT","Lorem ipsum dolor sit amet, consectetur adipiscing elit",R.drawable.intro5)); IntroAdapter adapter = new IntroAdapter(this,items); recyclerView.setAdapter(adapter); } }
Don’t forget to add images in the drawable folder!
Leave A Comment