AppIntro (OnBoard) Screen - Kotlin
Introduction:
App Intro/Onboard screen is mainly to display the key features of our app to users while launching it, in a sweet way. Let's do that simply with TabLayout, ViewPager and its PageTransformer.
Design:
slide_page.xml
Desgin this layout with ViewPager and TabLayout to begin with.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/introLayout" 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:layout_above="@+id/tabLayout" /> <android.support.design.widget.TabLayout android:id="@+id/tabLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@+id/next" app:tabBackground="@drawable/tab_selector" app:tabGravity="center" app:tabIndicatorHeight="0dp" /> <TextView android:id="@+id/next" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_margin="15dp" android:text="@string/next" android:textAppearance="@android:style/TextAppearance.Medium" android:textColor="@color/colorPrimary" /> <TextView android:id="@+id/skip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_margin="15dp" android:text="@string/skip" android:textAppearance="@android:style/TextAppearance.Medium" android:textColor="@color/colorPrimary" /> </RelativeLayout>
intro_layout.xml
The layout have the design that will be displayed on each page of Viewpager.<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/third_layout" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@+id/description" android:text="@string/title" android:gravity="center" android:layout_margin="15dp" android:textColor="#000000" android:textSize="24sp"/> <TextView android:id="@+id/description" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="@string/description" android:gravity="center" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:layout_marginBottom="15dp" android:textSize="18sp"/> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/title" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:layout_marginTop="20dp" android:layout_marginBottom="5dp"> <ImageView android:id="@+id/introImage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@drawable/cycling"/> <ImageView android:id="@+id/iv_bike_shadow" android:layout_width="80dp" android:layout_height="8dp" android:layout_centerHorizontal="true" android:layout_below="@+id/introImage" android:layout_marginTop="30dp" android:src="@drawable/shadow"/> </RelativeLayout> </RelativeLayout>
Drawable Files:
tab_selector.xml:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/selected_dot" android:state_selected="true" /> <item android:drawable="@drawable/default_dot" /> </selector>
selected_dot.xml:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape android:innerRadius="0dp" android:shape="ring" android:thickness="4dp" android:useLevel="false"> <solid android:color="@color/colorPrimary"/> </shape> </item> </layer-list>
default_dot.xml:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape android:innerRadius="0dp" android:shape="ring" android:thickness="4dp" android:useLevel="false"> <solid android:color="@color/divider"/> </shape> </item> </layer-list>
shadow.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" > <solid android:color="@color/transparentBlack"/> </shape>
Values Files:
strings.xml:
Include the following in your strings.xml file.
<string name="next">Next</string> <string name="skip">Skip</string> <string name="continues">Continue</string> <string name="skip_pressed">Skip Pressed!!</string> <string name="description">How great is it to travel?
To meet new people, see new places, experience different cultures.</string>
<string name="title">Travel World</string>
colors.xml:
Include the following in your colors.xml
<color name="colorPrimary">#3F51B5</color> <color name="colorPrimaryDark">#303F9F</color> <color name="colorAccent">#FF4081</color> <color name="transparentBlack">#48000000</color> <color name="grey">#C0C0C0</color> <color name="white">#ffffff</color> <color name="divider">#e6e6e6</color>
Code:
AppIntroScreen.kt
In this Activity, we have to initialize TabLayout with Viewpager. Also we have to set the adapter to the ViewPager. Here, we have extended FragmentPagerAdapter for Adapter class. Then we have to set our custom PageTransformer to the ViewPager to perform animation while scrolling the pages.
class AppIntroScreen : AppCompatActivity(), View.OnClickListener { val mResources = intArrayOf(R.drawable.cycling, R.drawable.airplane, R.drawable.kick_scooter, R.drawable.firefighter) lateinit var adapter: SlidingPagerAdapter var currentTab = 0 var tabCount = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.slide_page) tabCount = mResources.size adapter = SlidingPagerAdapter(supportFragmentManager, mResources) viewPager.adapter = adapter val pageTransformer = ParallaxTransformer() viewPager.setPageTransformer(true, pageTransformer) tabLayout.setupWithViewPager(viewPager) tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { override fun onTabReselected(tab: TabLayout.Tab?) { } override fun onTabUnselected(tab: TabLayout.Tab?) { } override fun onTabSelected(tab: TabLayout.Tab?) { viewPager.currentItem = tab!!.position } }) viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrollStateChanged(state: Int) { } override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { currentTab = position + 1 if (currentTab == tabCount) { skip.text = getString(R.string.continues) } else { skip.text = getString(R.string.skip) } } override fun onPageSelected(position: Int) { } }) next.setOnClickListener(this) skip.setOnClickListener(this) } override fun onClick(v: View?) { when (v?.id) { R.id.next -> { if (currentTab == tabCount) { skip.text = getString(R.string.continues) } else { skip.text = getString(R.string.skip) viewPager.currentItem = currentTab } } R.id.skip -> { Toast.makeText(this@AppIntroScreen, getString(R.string.skip_pressed), Toast.LENGTH_SHORT).show() // Proceed to Main/Home Activity of the App } } } } class SlidingPagerAdapter(fragmentManager: FragmentManager?, val mResources: IntArray) : FragmentPagerAdapter(fragmentManager) { override fun getItem(position: Int): Fragment { return IntroPage().newInstance(position) } override fun getCount(): Int { return mResources.size } }
IntroPage.kt (Fragment)
In this Fragment class, we have to change the images, based on the position of the ViewPager's Adapter.
class IntroPage : Fragment() { var position = 0 val mResources = intArrayOf(R.drawable.cycling, R.drawable.airplane, R.drawable.kick_scooter, R.drawable.firefighter) fun newInstance(position: Int): IntroPage { val fragment = IntroPage() val arguments = Bundle() arguments.putInt("POSITION", position) fragment.setArguments(arguments) return fragment } override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater!!.inflate(R.layout.intro_layout, container, false); } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) val args = arguments position = args.getInt("POSITION") introImage.setImageDrawable(resources.getDrawable(mResources[position])) } }
ParallaxTransformer.kt
Here, we can play with animation of our choice.
class ParallaxTransformer : ViewPager.PageTransformer { override fun transformPage(view: View, position: Float) { val absPosition = Math.abs(position) if (position < -1) { // This page is way off-screen to the left. view.alpha = 1f } else if (position <= 1) { val image = view.findViewById<ImageView>(R.id.introImage) image?.apply { setScaleX(1.0f - absPosition * 2) setScaleY(1.0f - absPosition * 2) setAlpha(1.0f - absPosition * 2) } val shadow = view.findViewById<ImageView>(R.id.shadow) shadow?.apply { setScaleX(1.0f - absPosition * 2) setScaleY(1.0f - absPosition * 2) setAlpha(1.0f - absPosition * 2) } } else { // This page is way off-screen to the right. view.alpha = 1f } } }
I am getting an error with the View.onClickListener at the top of the class.
ReplyDeleteHave you imported android.view.View?? Also kindly check whether you used OnClickListener or onClickListener..
Delete