Androidブートページ実装


背景
もし私たちのアプリにいくつかのリソースをロードする必要がある場合、あるいは移行したインタフェースがメインインタフェースにそんなに突然表示されないようにする必要がある場合、私たちはブートページという概念を使用する必要があります.ブートページの間にいくつかのリソースをロードすることで、ユーザーに仕事をさせないなど、ユーザーに悪い体験を与えることになります.Androidのガイドページの実現には主に4つの方法があります.
  • Splashインターフェース
  • ViewPager
  • ViewFlipper
  • ScrollView

  • 次は順番に彼を実現します.
    Splashインタフェース
    この方法は最も簡単な方法であり,主界面に遅延したStartを行うことであり,この実現はHandlerを用いて達成できる.
    package com.xjh.bootpagedemo.splash
    
    import android.content.Intent
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.os.Handler
    import com.xjh.bootpagedemo.MainActivity
    import com.xjh.bootpagedemo.R
    
    class SplashActivity : AppCompatActivity() {
    
        companion object {
            private val DELAY_TIME = 3000L
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_splash)
            Handler().postDelayed({
                startActivity(Intent(this, MainActivity::class.java))
                finish()
            }, DELAY_TIME)
        }
    }
    
    

    ViewFlipper
    もし私たちがまたページをめくる効果がほしいならば、このようにアプリの製品紹介に使うことができて、このようにView Flipperと結びつけて実現しなければなりません.これはAndroidが持っているマルチインタフェースの展示Viewです.XMLで直接定義すればよい.
    
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ViewFlipper
            android:id="@+id/viewFlipper"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@color/colorAccent" />
    
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@color/colorPrimary" />
    
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/colorPrimaryDark">
    
                <Button
                    android:id="@+id/btn"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentBottom="true"
                    android:layout_centerHorizontal="true"
                    android:layout_marginBottom="60dp"
                    android:gravity="center"
                    android:text="    "
                    android:textSize="22sp" />
    
            RelativeLayout>
    
        ViewFlipper>
    
        <LinearLayout
            android:id="@+id/indicator"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal|bottom"
            android:layout_marginBottom="30dp"
            android:orientation="horizontal" />
    
    FrameLayout>
    

    Activityでも簡単で、ジェスチャーを傍受してどの方向にスライドしているのかを判断し、関連する方法を呼び出すだけで実現でき、ViewFlipperが変化したときに対応するインジケータを変更すればよい.
    package com.xjh.bootpagedemo.viewflipper
    
    import android.app.ActionBar
    import android.content.Intent
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.util.TypedValue
    import android.view.GestureDetector
    import android.view.MotionEvent
    import android.view.View
    import androidx.core.view.get
    import com.xjh.bootpagedemo.MainActivity
    import com.xjh.bootpagedemo.R
    import kotlinx.android.synthetic.main.activity_view_flipper.*
    import kotlinx.android.synthetic.main.activity_view_pager.*
    import kotlinx.android.synthetic.main.activity_view_pager.indicator
    import kotlinx.android.synthetic.main.fragment_content.view.*
    
    class ViewFlipperActivity : AppCompatActivity(), GestureDetector.OnGestureListener {
    
        private lateinit var gestureDetector: GestureDetector
        private var index = 0
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_view_flipper)
            btn.setOnClickListener {
                startActivity(Intent(this, MainActivity::class.java))
            }
            initIndicator()
        }
    
        private fun initIndicator() {
            val width =
                TypedValue.applyDimension(
                    TypedValue.COMPLEX_UNIT_DIP,
                    20f,
                    resources.displayMetrics
                ).toInt()
            val lp = ActionBar.LayoutParams(width, width)
            lp.rightMargin = 2 * width
            lp.leftMargin = 2 * width
            for (i in 0 until viewFlipper.childCount) {
                val view = View(this)
                view.id = i
                view.setBackgroundResource(if (i == 0) R.drawable.dot_focus else R.drawable.dot_normal)
                view.layoutParams = lp
                indicator.addView(view, i)
            }
    
            gestureDetector = GestureDetector(this)
        }
    
        override fun onShowPress(e: MotionEvent?) {
    
        }
    
        override fun onSingleTapUp(e: MotionEvent?): Boolean {
            return false
        }
    
        override fun onDown(e: MotionEvent?): Boolean {
            return false
        }
    
        override fun onFling(
            e1: MotionEvent?,
            e2: MotionEvent?,
            velocityX: Float,
            velocityY: Float
        ): Boolean {
            e1?.let { a ->
                e2?.let { b ->
                    if (a.x > b.x) {
                        viewFlipper.showNext()
                        index = if (index < 2) index + 1 else 0
                        changeIndicator()
                        return true
                    } else if (a.x < b.x) {
                        viewFlipper.showNext()
                        index = if (index > 0) index - 1 else 2
                        changeIndicator()
                        return true
                    }
                }
            }
            return false
        }
    
        private fun changeIndicator() {
            for (i in 0 until viewFlipper.childCount) {
                indicator[i].setBackgroundResource(
                    if (i == index) R.drawable.dot_focus else R.drawable.dot_normal
                )
            }
        }
    
        override fun onScroll(
            e1: MotionEvent?,
            e2: MotionEvent?,
            distanceX: Float,
            distanceY: Float
        ): Boolean {
            return false
        }
    
        override fun onLongPress(e: MotionEvent?) {
    
        }
    
        override fun onTouchEvent(event: MotionEvent?): Boolean {
            return gestureDetector.onTouchEvent(event)
        }
    }
    
    

    今ここで私が書いたのはオフセットがあれば変化して、本当の実現の中で私たちは彼に一定のしきい値を与えることができて、そのしきい値に達してこそページの変化を行うことができます.
    ViewPager
    ViewFlipperが実装したガイドページのページめくりを実現するにはいくつかの突起があり、直接飛び越えたので、グラデーションの効果は一つもなく、グラデーションの効果を実現するにはViewPagerを使用しなければならない.現在のページに基づいて異なるFragmentを表示し、ページをめくって指示標の状態を変えるだけでいいです.activity_view_pager.xml
    
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <androidx.viewpager.widget.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <LinearLayout
            android:id="@+id/indicator"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal|bottom"
            android:layout_marginBottom="30dp"
            android:orientation="horizontal" />
    
    FrameLayout>
    

    ここでは特に簡単な色でどのFragmentにあるかを区別します.fragment_content.xml
    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/contentRLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <Button
            android:id="@+id/btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="60dp"
            android:gravity="center"
            android:text="    "
            android:textSize="22sp" />
    
    RelativeLayout>
    

    そしてFragmentを実現し,その中で伝達されたパラメータによってどの色がロードされているかを判断し,最後の1枚であればボタンを表示する状態にする.ContentFragment.kt
    package com.xjh.bootpagedemo.viewpager
    
    import android.content.Intent
    import android.os.Bundle
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import androidx.fragment.app.Fragment
    import com.xjh.bootpagedemo.MainActivity
    import com.xjh.bootpagedemo.R
    import kotlinx.android.synthetic.main.fragment_content.view.*
    
    class ContentFragment : Fragment() {
    
        private val bgRes = arrayOf(R.color.colorAccent, R.color.colorPrimary, R.color.colorPrimaryDark)
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            val view = inflater.inflate(R.layout.fragment_content, null)
            arguments?.getInt("index")?.let {
                view.contentRLayout.setBackgroundResource(bgRes[it])
                view.btn.setOnClickListener {
                    startActivity(Intent(activity, MainActivity::class.java))
                }
                view.btn.visibility = if (it == 2) View.VISIBLE else View.GONE
            }
            return view
        }
    }
    

    すぐにViewPagerのAdapterを実現しますが、実は簡単です.FragmentPagerAdapterに継承し、関連するデータリストを渡せばいいので、対応する戻りはリストのいずれかでいいです.ViewPagerAdapter.kt
    package com.xjh.bootpagedemo.viewpager
    
    import androidx.fragment.app.Fragment
    import androidx.fragment.app.FragmentManager
    import androidx.fragment.app.FragmentPagerAdapter
    
    class ViewPagerAdapter(fm: FragmentManager, private var fragments: List<Fragment>) :
        FragmentPagerAdapter(fm) {
    
        override fun getCount(): Int {
            return fragments.size
        }
    
        override fun getItem(position: Int): Fragment {
            return fragments[position]
        }
    }
    

    最後に最も重要なActivityは、対応する必要なFragmentをすべて実現し、それによって関連するAdapterを実現し、ViewPagerにロードすることです.最後に、関連するナビゲーションバーを初期化し、ViewPagerの変化を監視する必要があります.ViewPagerActivity.kt
    package com.xjh.bootpagedemo.viewpager
    
    import android.app.ActionBar
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.util.TypedValue
    import android.view.View
    import androidx.core.view.get
    import androidx.core.view.marginLeft
    import androidx.core.view.marginRight
    import androidx.core.view.marginTop
    import androidx.fragment.app.Fragment
    import androidx.viewpager.widget.PagerAdapter
    import androidx.viewpager.widget.ViewPager
    import com.xjh.bootpagedemo.R
    import kotlinx.android.synthetic.main.activity_view_pager.*
    
    class ViewPagerActivity : AppCompatActivity() {
    
        private lateinit var adapter: PagerAdapter
        private val fragments = ArrayList<Fragment>()
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_view_pager)
    
            for (index in 0..2) {
                val fragment = ContentFragment()
                val bundle = Bundle()
                bundle.putInt("index", index)
                fragment.arguments = bundle
                fragments.add(fragment)
            }
    
            adapter = ViewPagerAdapter(supportFragmentManager, fragments)
            viewPager.adapter = adapter
            initIndicator()
            viewPager.setOnPageChangeListener(object : ViewPager.OnPageChangeListener {
                override fun onPageScrollStateChanged(state: Int) {
    
                }
    
                override fun onPageScrolled(
                    position: Int,
                    positionOffset: Float,
                    positionOffsetPixels: Int
                ) {
                    for (i in 0 until fragments.size) {
                        indicator[i].setBackgroundResource(
                            if (i == position) R.drawable.dot_focus else R.drawable.dot_normal
                        )
                    }
                }
    
                override fun onPageSelected(position: Int) {
    
                }
    
            })
        }
    
        private fun initIndicator() {
            val width =
                TypedValue.applyDimension(
                    TypedValue.COMPLEX_UNIT_DIP,
                    20f,
                    resources.displayMetrics
                ).toInt()
            val lp = ActionBar.LayoutParams(width, width)
            lp.rightMargin = 2 * width
            lp.leftMargin = 2 * width
            for (i in 0 until fragments.size) {
                val view = View(this)
                view.id = i
                view.setBackgroundResource(if (i == 0) R.drawable.dot_focus else R.drawable.dot_normal)
                view.layoutParams = lp
                indicator.addView(view, i)
            }
        }
    
    
    }
    
    

    ScrollView
    もし私たちがドラッグ効果のガイドページを実現するにはどうすればいいのでしょうか.ここではScrollViewを使用します.単純にドラッグを使用するだけであれば、ScrollViewコントロールを直接使用することができます.アニメーション効果を追加するには、カスタムコントロールを使用してこの操作を完了する必要があります.まず、私たちは上下にスライドしているので、onScrollChangedメソッドでは垂直方向のオフセットに関心を持ってインタフェースに渡し、Activityに渡して処理する必要があります.MyScrollView.kt
    package com.xjh.bootpagedemo.scrollview
    
    import android.content.Context
    import android.util.AttributeSet
    import android.widget.ScrollView
    
    class MyScrollView(context: Context, attrs: AttributeSet?) : ScrollView(context, attrs) {
    
        private lateinit var onScrollViewListener: OnScrollChangeListener
    
        override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) {
            super.onScrollChanged(l, t, oldl, oldt)
            onScrollViewListener.onScrollChange(t, oldt)
        }
    
        interface OnScrollChangeListener {
            fun onScrollChange(top: Int, oldTop: Int)
        }
    
        fun setOnScrollChangeListener(onScrollChangeListener: OnScrollChangeListener) {
            this.onScrollViewListener = onScrollChangeListener
        }
    }
    

    次に、このコントロールを直接使用して、必要な背景activityを定義します.scroll_view.xml
    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.xjh.bootpagedemo.scrollview.MyScrollView
            android:id="@+id/scrollView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/colorAccent">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center_horizontal"
                android:orientation="vertical">
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="100dp"
                    android:text="     "
                    android:textSize="20sp"
                    android:textStyle="bold" />
    
                <ImageView
                    android:layout_width="150dp"
                    android:layout_height="150dp"
                    android:layout_marginTop="20dp"
                    android:src="@mipmap/ic_launcher" />
    
                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_marginTop="50dp"
                    android:src="@drawable/dot_white" />
    
                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_marginTop="50dp"
                    android:src="@drawable/dot_white" />
    
                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_marginTop="50dp"
                    android:src="@drawable/dot_white" />
    
                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_marginTop="50dp"
                    android:src="@drawable/dot_white" />
    
                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_marginTop="50dp"
                    android:src="@drawable/dot_white" />
    
                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_marginTop="50dp"
                    android:src="@drawable/dot_white" />
    
                <LinearLayout
                    android:id="@+id/animLLayout"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="50dp"
                    android:gravity="center"
                    android:orientation="horizontal"
                    android:visibility="invisible">
    
                    <ImageView
                        android:layout_width="50dp"
                        android:layout_height="50dp"
                        android:layout_margin="20dp"
                        android:src="@drawable/dot_yellow" />
    
                    <ImageView
                        android:layout_width="50dp"
                        android:layout_height="50dp"
                        android:layout_margin="20dp"
                        android:src="@drawable/dot_blue" />
    
                    <ImageView
                        android:layout_width="50dp"
                        android:layout_height="50dp"
                        android:layout_margin="20dp"
                        android:src="@drawable/dot_black" />
    
                LinearLayout>
    
                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_marginTop="50dp"
                    android:src="@drawable/dot_white" />
    
                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_marginTop="50dp"
                    android:src="@drawable/dot_white" />
    
                <Button
                    android:id="@+id/btn"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="50dp"
                    android:layout_marginBottom="30dp"
                    android:gravity="center"
                    android:text="    "
                    android:textSize="22sp" />
            LinearLayout>
        com.xjh.bootpagedemo.scrollview.MyScrollView>
    
    RelativeLayout>
    

    その後、このコントロールをそのまま使用して、上下スライドのずれ量で上に移動するか下に移動するかを判断し、判断時に現在の状態に対する判断を加えて、繰り返し設定状態を防止しました.ScrollViewActivity.kt
    package com.xjh.bootpagedemo.scrollview
    
    import android.content.Intent
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.util.Log
    import android.view.View
    import android.view.animation.AnimationUtils
    import com.xjh.bootpagedemo.MainActivity
    import com.xjh.bootpagedemo.R
    import kotlinx.android.synthetic.main.activity_scroll_view.*
    import kotlinx.android.synthetic.main.activity_view_flipper.*
    import kotlinx.android.synthetic.main.activity_view_flipper.btn
    
    class ScrollViewActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_scroll_view)
    
            btn.setOnClickListener {
                startActivity(Intent(this, MainActivity::class.java))
            }
            val context = this
            scrollView.setOnScrollChangeListener(object : MyScrollView.OnScrollChangeListener {
                override fun onScrollChange(top: Int, oldTop: Int) {
                    if (top > oldTop && animLLayout.visibility == View.INVISIBLE) {
                        val anim = AnimationUtils.loadAnimation(context, R.anim.show)
                        animLLayout.visibility = View.VISIBLE
                        animLLayout.startAnimation(anim)
                    } else if (top < oldTop && animLLayout.visibility == View.VISIBLE) {
                        val anim = AnimationUtils.loadAnimation(context, R.anim.close)
                        animLLayout.visibility = View.INVISIBLE
                        animLLayout.startAnimation(anim)
                    }
                }
            })
        }
    }
    
    

    プロジェクトGithubアドレス:転送ゲート