Android开发 ViewPager2
<h1><span style="color: rgba(0, 128, 128, 1)">前言</span></h1><p> ViewPage2是ViewPage的取代者,解决了一些解决了其前辈ViewPage的大部分难题,包括从右到左的布局支持,垂直方向,可修改的Fragment集合等。从易用性上来说ViewPage2的确会比ViewPage更简单,并且它实际上是使用RecyclerView实现的。源码里可以很容易看到,另外它的适配器也是RecyclerView.Adapter。</p>
<h1><span style="color: rgba(0, 128, 128, 1)">特别注意</span></h1>
<p>在developer官网上,已经说明了 ViewPager2在导航键翻页(TV模式),根本没实现。所有,如果你的是TV应用,原则上不建议使用ViewPager2开发(TV应用用它浪费时间),而是使用ViewPager。</p>
<p>这下面说需要完善,都2022年了,居然还没完善。 本着钻研的精神(钻牛角尖),本博客最下面给了一个不太稳定的方法实现焦点的触控。 </p>
<p><img src="https://img2022.cnblogs.com/blog/1497956/202204/1497956-20220408112558646-421558356.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<h1><span style="color: rgba(0, 128, 128, 1)">依赖</span></h1>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">dependencies {
implementation </span>"androidx.viewpager2:viewpager2:1.0.0"<span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">使用</span><span style="color: rgba(0, 128, 128, 1)">RecyclerView.Adapter</span></h1>
<p>使用场景一般是首页图片轮播,或者引导页面</p>
<p>xml</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">androidx.constraintlayout.widget.ConstraintLayout
</span><span style="color: rgba(255, 0, 0, 1)">xmlns:android</span><span style="color: rgba(0, 0, 255, 1)">="http://schemas.android.com/apk/res/android"</span><span style="color: rgba(255, 0, 0, 1)">
xmlns:app</span><span style="color: rgba(0, 0, 255, 1)">="http://schemas.android.com/apk/res-auto"</span><span style="color: rgba(255, 0, 0, 1)">
xmlns:tools</span><span style="color: rgba(0, 0, 255, 1)">="http://schemas.android.com/tools"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_width</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_height</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span><span style="color: rgba(255, 0, 0, 1)">
tools:context</span><span style="color: rgba(0, 0, 255, 1)">=".viewpage2.ViewPager2Activity"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">androidx.viewpager2.widget.ViewPager2
</span><span style="color: rgba(255, 0, 0, 1)">android:id</span><span style="color: rgba(0, 0, 255, 1)">="@+id/imagePager"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_width</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_height</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span><span style="color: rgba(255, 0, 0, 1)">
android:orientation</span><span style="color: rgba(0, 0, 255, 1)">="horizontal"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">androidx.constraintlayout.widget.ConstraintLayout</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
</div>
<p>Adapter</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span> ViewPager2Adapter1() : RecyclerView.Adapter<ViewPager2Adapter1.ViewHolder><span style="color: rgba(0, 0, 0, 1)">() {
val mImageList </span>= mutableListOf<Int><span style="color: rgba(0, 0, 0, 1)">()
fun refreshData(list :MutableList</span><Int>?<span style="color: rgba(0, 0, 0, 1)">){
list</span>?<span style="color: rgba(0, 0, 0, 1)">.let {
mImageList.addAll(list)
}
notifyDataSetChanged()
}
</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView </span>= itemView.findViewById<ImageView><span style="color: rgba(0, 0, 0, 1)">(R.id.image)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPager2Adapter1.ViewHolder {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_view_pager_demo_1, parent, <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">))
}
override fun onBindViewHolder(holder: ViewPager2Adapter1.ViewHolder, position: Int) {
holder.imageView.setImageResource(mImageList)
}
override fun getItemCount(): Int </span>=<span style="color: rgba(0, 0, 0, 1)"> mImageList.size
}</span></pre>
</div>
<p>activity</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ViewPager2Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle</span>?<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_pager2)
val adapter </span>=<span style="color: rgba(0, 0, 0, 1)"> ViewPager2Adapter1()
val imagePager </span>= findViewById<ViewPager2><span style="color: rgba(0, 0, 0, 1)">(R.id.imagePager)
imagePager.adapter </span>=<span style="color: rgba(0, 0, 0, 1)"> adapter
adapter.refreshData(mutableListOf(R.drawable.ic_landscape_1, R.drawable.ic_landscape_2, R.drawable.ic_landscape_3, R.drawable.ic_landscape_4))
}
}</span></pre>
</div>
<p>效果图</p>
<p><img src="https://img2022.cnblogs.com/blog/1497956/202203/1497956-20220303164438063-1262273333.gif" alt=""></p>
<p> </p>
<h1> </h1>
<h1><span style="color: rgba(0, 128, 128, 1)">使用FragmentStateAdapter</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">使用场景一般是主页tab分页,每一页都是Fragment</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span> MessageAdapter(fragments: List<Fragment><span style="color: rgba(0, 0, 0, 1)">, fragment: Fragment) : FragmentStateAdapter(fragment) {
</span><span style="color: rgba(0, 0, 255, 1)">private</span> var mFragments :List<Fragment> =<span style="color: rgba(0, 0, 0, 1)"> fragments
override fun getItemCount() </span>=<span style="color: rgba(0, 0, 0, 1)"> mFragments.size
override fun createFragment(position: Int) </span>=<span style="color: rgba(0, 0, 0, 1)"> mFragments
}</span></pre>
</div>
<p><span>上面的代码是在Fragment中使用,如果需要在activity中使用就使用另一个构造方法</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> FragmentStateAdapter(@NonNull FragmentActivity fragmentActivity)</pre>
</div>
<p><span>然后是添加到ViewPager2里</span></p>
<div class="cnblogs_code">
<pre> val fragmentList =<span style="color: rgba(0, 0, 0, 1)"> listOf(AlertFragment.newInstance(), FamilyFragment.newInstance(), NoticeFragment.newInstance())
val adapter </span>= MessageAdapter(fragmentList, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">)
mBinding.viewPager.adapter </span>= adapter</pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">与TabLayout配合使用</span><code dir="ltr"><span class="tag"><br></span></code></h1>
<div class="cnblogs_code">
<pre>TabLayout tabLayout =<span style="color: rgba(0, 0, 0, 1)"> view.findViewById(R.id.tab_layout);
</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> TabLayoutMediator(tabLayout, viewPager,
(tab, position) </span>-> tab.setText("OBJECT " + (position + 1<span style="color: rgba(0, 0, 0, 1)">))
).attach();</span></pre>
</div>
<p> 但是请注意!在添加数据的时候不需要在newTab了,参考如下代码</p>
<div class="cnblogs_code">
<pre> override fun onViewCreated(view: View, savedInstanceState: Bundle?<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onViewCreated(view, savedInstanceState)
val fragmentList </span>=<span style="color: rgba(0, 0, 0, 1)"> listOf(AlertFragment.newInstance(), FamilyFragment.newInstance(), NoticeFragment.newInstance())
val adapter </span>= MessageAdapter(fragmentList, <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">)
mBinding.viewPager.adapter </span>=<span style="color: rgba(0, 0, 0, 1)"> adapter
val tabIconArray </span>=<span style="color: rgba(0, 0, 0, 1)"> intArrayOf(R.drawable.message_ic_alert_3, R.drawable.message_ic_family_3, R.drawable.message_ic_notice_3)
TabLayoutMediator(mBinding.tabLayout, mBinding.viewPager) { tab, position </span>-><span style="color: rgba(0, 0, 0, 1)">
}.attach()
</span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> ((index, itemData)in tabIconArray.withIndex()) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里不需要newTab(),因为上面的TabLayoutMediator已经创建好了tab</span>
val tab: TabLayout.Tab? =<span style="color: rgba(0, 0, 0, 1)"> mBinding.tabLayout.getTabAt(index)
val binding </span>= MessageItemMessageBinding.inflate(layoutInflater, mBinding.tabLayout, <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">)
binding.icon.setImageResource(itemData)
tab</span>?.customView =<span style="color: rgba(0, 0, 0, 1)"> binding.root
mItemRedDotArray.add(binding.redDot)
}
initListener()
}</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">禁用左右滑动切换</span></h1>
<div class="cnblogs_code">
<pre>viewPager.setUserInputEnabled(false)</pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">设置方向</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">横</span></p>
<div class="cnblogs_code">
<pre>android:orientation="horizontal"</pre>
</div>
<p><span style="background-color: rgba(255, 255, 255, 1); color: rgba(0, 0, 0, 1)">竖</span></p>
<div class="cnblogs_code">
<pre>android:orientation="vertical"</pre>
</div>
<h1><span style="background-color: rgba(255, 255, 255, 1)"><span style="color: rgba(0, 128, 128, 1)">设置滑动方向</span></span></h1>
<p><span style="background-color: rgba(255, 255, 255, 1); color: rgba(0, 0, 0, 1)">从左到右</span></p>
<div class="cnblogs_code">
<pre>android:layoutDirection="ltr"</pre>
</div>
<p>从右到左</p>
<div class="cnblogs_code">
<pre>android:layoutDirection="rtl"</pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">翻页结果监听</span></h1>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> imagePager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageScrollStateChanged(state: Int) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onPageScrollStateChanged(state)
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
表示ViewPager2处于空闲、稳定状态。当前页面完全可见,并且没有动画正在进行中。
SCROLL_STATE_IDLE = 0
表示ViewPager2当前正在被用户拖动,或者通过虚假拖动功能以编程方式进行拖动。
SCROLL_STATE_DRAGGING = 1
表示ViewPager2正在稳定到最终位置。
SCROLL_STATE_SETTLING = 2
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
Log.e(</span>"zh", "滚动状态变化 : state = $state"<span style="color: rgba(0, 0, 0, 1)">)
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onPageScrolled(position, positionOffset, positionOffsetPixels)
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
position – 当前显示的第一页的位置索引。如果 positionOffset 不为零,则页面位置+1 将可见。
positionOffset – 表示在位置处与页面的偏移量, 取值范围
positionOffsetPixels – 以像素为单位的值,指示与位置的偏移量。
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
Log.e(</span>"zh", "正在翻页滚动 : position = $position positionOffset = $positionOffset positionOffsetPixels = $positionOffsetPixels"<span style="color: rgba(0, 0, 0, 1)">)
}
override fun onPageSelected(position: Int) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onPageSelected(position)
Log.e(</span>"zh", "当前页面 : position = $position"<span style="color: rgba(0, 0, 0, 1)">)
}
})</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">翻页动画</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">ViewPager2的翻页动画稍微一点点复杂,需要一些耐心理解.</span></p>
<p><span style="color: rgba(0, 0, 0, 1)">首先动画的实现是依靠</span> ViewPager2.PageTransformer 接口回调实现的, 在下面的代码中有注释说明,</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> imagePager.setPageTransformer(object : ViewPager2.PageTransformer {
override fun transformPage(page: View, position: Float) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (position < -1) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 范围 -无穷数 到 -1</span><span style="color: rgba(0, 128, 0, 1)">
// 此页面在左侧屏幕外,在这个位置的view已经看不到了,一般不需要处理,只要给初始默认值就行</span><span style="color: rgba(0, 0, 0, 1)">
Log.e(</span>"zh", "此页面在左侧屏幕外: $position"<span style="color: rgba(0, 0, 0, 1)">)
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (position <= 1) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">范围-1 到 1</span>
<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
* 在这个位置的view正在在屏幕中显示,是需要实现动画效果的view
* 这里其实有2个view会交替回调, 分别是position小于0的左边的view 与 position大于0的右边的view
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (position < 0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">viewpager左边item的显示</span>
Log.e("zh", "viewpager左边item的显示 位置 = $position view的内存地址 = ${page}"<span style="color: rgba(0, 0, 0, 1)">)
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">viewpager右边item的显示</span>
Log.e("zh", "viewpager右边item的显示 位置 = $position view的内存地址 = ${page}"<span style="color: rgba(0, 0, 0, 1)">)
}
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">范围 1 到 +无穷数
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 此页面在右侧屏幕外,在这个位置的view已经看不到了,一般不需要处理,只要给初始默认值就行</span>
Log.e("zh", "此页面在右侧屏幕外: $position"<span style="color: rgba(0, 0, 0, 1)">)
}
}
})</span></pre>
</div>
<p>如果你看了上面的注释依然不太明白,我们可以用图片解释一下</p>
<h3>图片1</h3>
<p><img src="https://img2022.cnblogs.com/blog/1497956/202203/1497956-20220303201153728-1934604448.png" alt="" width="714" height="598" loading="lazy"></p>
<h3>图片2</h3>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>理解这张图片很重要! </strong></span>这张图片中的效果出现的时候,就是position 正在返回 -1 到 1的值. </p>
<p>这正是我们需要实现动画效果(透明度,放大缩小,旋转抛出等等效果)的时候</p>
<p> <img src="https://img2022.cnblogs.com/blog/1497956/202203/1497956-20220303201908806-1457385566.png" alt="" loading="lazy"></p>
<h2>举例一个淡入淡出动画效果</h2>
<p>在上面说明了动画的取值范围后,这里举例一个最容易实现的动画,淡入淡出动画.</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> imagePager.setPageTransformer(object : ViewPager2.PageTransformer {
override fun transformPage(page: View, position: Float) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (position < -1) {<span style="color: rgba(0, 0, 0, 1)">
page.alpha </span>=<span style="color: rgba(0, 0, 0, 1)"> 0f
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (position <= 1) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">范围-1 到 1</span>
<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
* 求绝对值,作为动画的变量值
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
val animationValue: Float </span>=<span style="color: rgba(0, 0, 0, 1)"> Math.abs(position)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (position < 0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">viewpager左边item的显示</span>
page.alpha = 1 -<span style="color: rgba(0, 0, 0, 1)"> animationValue
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">viewpager右边item的显示</span>
page.alpha = 1 -<span style="color: rgba(0, 0, 0, 1)"> animationValue
}
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> { <br> page.alpha =<span style="color: rgba(0, 0, 0, 1)"> 0f
}
}
})</span></pre>
</div>
<p>效果图</p>
<p><img src="https://img2022.cnblogs.com/blog/1497956/202203/1497956-20220303210052429-2020853800.gif" alt=""></p>
<h1>举一反三实现旋转与缩小放大动画效果</h1>
<p>代码</p>
<div class="cnblogs_code">
<pre> override fun onCreate(savedInstanceState: Bundle?<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_pager2)
val adapter </span>=<span style="color: rgba(0, 0, 0, 1)"> ViewPager2Adapter1()
val imagePager </span>= findViewById<ViewPager2><span style="color: rgba(0, 0, 0, 1)">(R.id.imagePager)
imagePager.adapter </span>=<span style="color: rgba(0, 0, 0, 1)"> adapter
adapter.refreshData(mutableListOf(R.drawable.ic_landscape_1, R.drawable.ic_landscape_2, R.drawable.ic_landscape_3, R.drawable.ic_landscape_4))
imagePager.setPageTransformer(object : ViewPager2.PageTransformer {
override fun transformPage(page: View, position: Float) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (position < -1<span style="color: rgba(0, 0, 0, 1)">) {
page.alpha </span>=<span style="color: rgba(0, 0, 0, 1)"> 0f
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (position <= 1) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">范围-1 到 1</span>
<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
* 求绝对值,作为动画的变量值
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
val animationValue: Float </span>=<span style="color: rgba(0, 0, 0, 1)"> Math.abs(position)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (position < 0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">viewpager左边item的显示</span>
page.alpha = 1 -<span style="color: rgba(0, 0, 0, 1)"> animationValue
setRotate(page, animationValue)
setScale(page, animationValue)
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">viewpager右边item的显示</span>
page.alpha = 1 -<span style="color: rgba(0, 0, 0, 1)"> animationValue
setRotate(page, animationValue)
setScale(page, animationValue)
}
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
page.alpha </span>=<span style="color: rgba(0, 0, 0, 1)"> 0f
}
}
})
}
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 旋转效果
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
fun setRotate(view: View, value: Float) {
view.rotationX </span>= 0.5f<span style="color: rgba(0, 0, 0, 1)">
view.rotationY </span>= 0.5f<span style="color: rgba(0, 0, 0, 1)">
view.rotation </span>= 360 *<span style="color: rgba(0, 0, 0, 1)"> value
}
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 缩放效果
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
fun setScale(view: View, value: Float) {
view.scaleX </span>= 1 -<span style="color: rgba(0, 0, 0, 1)"> value
view.scaleY </span>= 1 -<span style="color: rgba(0, 0, 0, 1)"> value
}</span></pre>
</div>
<p>效果图</p>
<p><img src="https://img2022.cnblogs.com/blog/1497956/202203/1497956-20220303210459985-323161782.gif" alt=""></p>
<h2>看看google给的例子</h2>
<p>例子1</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> DepthPageTransformer <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> PageTransformer {
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">float</span> MIN_SCALE = 0.75f<span style="color: rgba(0, 0, 0, 1)">;
@SuppressLint(</span>"NewApi"<span style="color: rgba(0, 0, 0, 1)">)
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> transformPage(View view, <span style="color: rgba(0, 0, 255, 1)">float</span><span style="color: rgba(0, 0, 0, 1)"> position) {
</span><span style="color: rgba(0, 0, 255, 1)">int</span> pageWidth =<span style="color: rgba(0, 0, 0, 1)"> view.getWidth();
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (position < -1) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> [-Infinity,-1)</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">This page is way off-screen to the left.</span>
view.setAlpha(0<span style="color: rgba(0, 0, 0, 1)">);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (position <= 0) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> [-1,0]Use </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">the default slide transition when moving to the left page</span>
view.setAlpha(1<span style="color: rgba(0, 0, 0, 1)">);
view.setTranslationX(</span>0<span style="color: rgba(0, 0, 0, 1)">);
view.setScaleX(</span>1<span style="color: rgba(0, 0, 0, 1)">);
view.setScaleY(</span>1<span style="color: rgba(0, 0, 0, 1)">);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (position <= 1) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> (0,1]</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Fade the page out.</span>
view.setAlpha(1 -<span style="color: rgba(0, 0, 0, 1)"> position);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Counteract the default slide transition</span>
view.setTranslationX(pageWidth * -<span style="color: rgba(0, 0, 0, 1)">position);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Scale the page down (between MIN_SCALE and 1)</span>
<span style="color: rgba(0, 0, 255, 1)">float</span> scaleFactor = MIN_SCALE + (1 -<span style="color: rgba(0, 0, 0, 1)"> MIN_SCALE)
</span>* (1 -<span style="color: rgba(0, 0, 0, 1)"> Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> (1,+Infinity]
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> This page is way off-screen to the right.</span>
view.setAlpha(0<span style="color: rgba(0, 0, 0, 1)">);
}
}
}</span></pre>
</div>
<p> 效果图</p>
<p><img src="https://img2022.cnblogs.com/blog/1497956/202203/1497956-20220304165728286-788027352.gif" alt=""></p>
<p> </p>
<p>例子2</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> ZoomOutPageTransformer <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> PageTransformer {
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">float</span> MIN_SCALE = 0.85f<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">float</span> MIN_ALPHA = 0.5f<span style="color: rgba(0, 0, 0, 1)">;
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> transformPage(View view, <span style="color: rgba(0, 0, 255, 1)">float</span><span style="color: rgba(0, 0, 0, 1)"> position) {
</span><span style="color: rgba(0, 0, 255, 1)">int</span> pageWidth =<span style="color: rgba(0, 0, 0, 1)"> view.getWidth();
</span><span style="color: rgba(0, 0, 255, 1)">int</span> pageHeight =<span style="color: rgba(0, 0, 0, 1)"> view.getHeight();
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (position < -1) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> [-Infinity,-1)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> This page is way off-screen to the left. </span>
view.setAlpha(0<span style="color: rgba(0, 0, 0, 1)">);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (position <= 1) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> [-1,1]
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Modify the default slide transition to
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> shrink the page as well </span>
<span style="color: rgba(0, 0, 255, 1)">float</span> scaleFactor = Math.max(MIN_SCALE, 1 -<span style="color: rgba(0, 0, 0, 1)"> Math.abs(position));
</span><span style="color: rgba(0, 0, 255, 1)">float</span> vertMargin = pageHeight * (1 - scaleFactor) / 2<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">float</span> horzMargin = pageWidth * (1 - scaleFactor) / 2<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (position < 0<span style="color: rgba(0, 0, 0, 1)">) {
view.setTranslationX(horzMargin </span>- vertMargin / 2<span style="color: rgba(0, 0, 0, 1)">);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
view.setTranslationX(</span>-horzMargin + vertMargin / 2<span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Scale the page down (between MIN_SCALE and 1) </span>
<span style="color: rgba(0, 0, 0, 1)"> view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Fade the page relative to its size. </span>
view.setAlpha(MIN_ALPHA + (scaleFactor -<span style="color: rgba(0, 0, 0, 1)"> MIN_SCALE)
</span>/ (1 - MIN_SCALE) * (1 -<span style="color: rgba(0, 0, 0, 1)"> MIN_ALPHA));
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> (1,+Infinity]
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> This page is way off-screen to the right. </span>
view.setAlpha(0<span style="color: rgba(0, 0, 0, 1)">);
}
}
} </span></pre>
</div>
<p>效果图</p>
<p><img src="https://img2022.cnblogs.com/blog/1497956/202203/1497956-20220304165913682-68116882.gif" alt=""></p>
<h1><span style="color: rgba(0, 128, 128, 1)">背景图片与ViewPager2 左右滑动的联动动画实现</span></h1>
<p>xml</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">ImageView
</span><span style="color: rgba(255, 0, 0, 1)">android:id</span><span style="color: rgba(0, 0, 255, 1)">="@+id/bgImage"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_width</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_height</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span><span style="color: rgba(255, 0, 0, 1)">
android:scaleX</span><span style="color: rgba(0, 0, 255, 1)">="1.1"</span><span style="color: rgba(255, 0, 0, 1)">
android:scaleY</span><span style="color: rgba(0, 0, 255, 1)">="1.1"</span><span style="color: rgba(255, 0, 0, 1)">
android:background</span><span style="color: rgba(0, 0, 255, 1)">="@mipmap/launcher_ic_bg"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">androidx.viewpager.widget.ViewPager
</span><span style="color: rgba(255, 0, 0, 1)">android:id</span><span style="color: rgba(0, 0, 255, 1)">="@+id/viewPage"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_width</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_height</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span><span style="color: rgba(255, 0, 0, 1)">
app:layout_constraintBottom_toBottomOf</span><span style="color: rgba(0, 0, 255, 1)">="parent"</span><span style="color: rgba(255, 0, 0, 1)">
app:layout_constraintTop_toBottomOf</span><span style="color: rgba(0, 0, 255, 1)">="parent"</span><span style="color: rgba(255, 0, 0, 1)">
app:layout_constraintVertical_bias</span><span style="color: rgba(0, 0, 255, 1)">="1.0"</span><span style="color: rgba(255, 0, 0, 1)">
tools:layout_editor_absoluteX</span><span style="color: rgba(0, 0, 255, 1)">="0dp"</span> <span style="color: rgba(0, 0, 255, 1)">/></span></pre>
</div>
<p>java</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> mBinding.viewPage.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
var lastPosition </span>= 0<span style="color: rgba(0, 0, 0, 1)">
var animationValue </span>=<span style="color: rgba(0, 0, 0, 1)"> 50f
lateinit var objectAnimator : ObjectAnimator
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
mDotsAdapter.setSelectItem(position)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (lastPosition ==<span style="color: rgba(0, 0, 0, 1)"> position){
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (lastPosition <<span style="color: rgba(0, 0, 0, 1)"> position){
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">右</span>
animationValue = animationValue -<span style="color: rgba(0, 0, 0, 1)">50f
objectAnimator</span>= ObjectAnimator.ofFloat(mBinding.bgImage,"translationX"<span style="color: rgba(0, 0, 0, 1)">, animationValue)
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">左</span>
animationValue = animationValue +<span style="color: rgba(0, 0, 0, 1)"> 50f
objectAnimator</span>= ObjectAnimator.ofFloat(mBinding.bgImage,"translationX"<span style="color: rgba(0, 0, 0, 1)">, animationValue)
}
objectAnimator.duration </span>= 500<span style="color: rgba(0, 0, 0, 1)">
objectAnimator.start()
lastPosition </span>=<span style="color: rgba(0, 0, 0, 1)"> position
}
override fun onPageSelected(position: Int) {
}
override fun onPageScrollStateChanged(state: Int) {
}
})</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">TV应用焦点与ViewPager2的兼容处理</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">在developer官网上,已经说明了 ViewPager2在导航键翻页(TV模式),根本没实现。所有,如果你的是TV应用,原则上不建议使用ViewPager2开发,而是使用ViewPager。 如果你非得杆上ViewPager2,下面这个代码也提供一个实现思路。但是十分不稳定</span></p>
<p><span style="color: rgba(0, 0, 0, 1)">TV应用特别是支持触控又支持遥控器的TV设备,</span><span>如何让焦点翻页? 特别是如何只使用遥控器方向键的情况下翻页呢?</span></p>
<div class="cnblogs_code">
<pre> override fun onCreate(savedInstanceState: Bundle?<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onCreate(savedInstanceState)
setContentView(mBinding.root)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">注册全局焦点监听 </span>
<span style="color: rgba(0, 0, 0, 1)"> mBinding.root.getViewTreeObserver().addOnGlobalFocusChangeListener(focusChangeListener)
}
override fun onDestroy() {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onDestroy()
mBinding.root.viewTreeObserver.removeOnGlobalFocusChangeListener(focusChangeListener)
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> val focusChangeListener: ViewTreeObserver.OnGlobalFocusChangeListener =<span style="color: rgba(0, 0, 0, 1)"> object : ViewTreeObserver.OnGlobalFocusChangeListener {
override fun onGlobalFocusChanged(oldFocus: View</span>?, newFocus: View?<span style="color: rgba(0, 0, 0, 1)">) {
Log.e(</span>"zh", "newFocus: ${newFocus} "<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (newFocus != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* viewPage里的当前焦点view的第3个父类其实是RecyclerView,这里需要准确找到它。
* 当前你也可以使用另一种方法,那就是继承ViewPage,然后让mRecyclerView 全局变量暴露到外包
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
mBinding.viewPage.findFocus()?.parent</span>?.parent?.parent?.let { recyclerView ->
<span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (recyclerView is RecyclerView) {
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 重点方法:findContainingViewHolder
* 根据当前焦点view找到当前的ViewHolder
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
val viewHolder </span>=<span style="color: rgba(0, 0, 0, 1)"> recyclerView.findContainingViewHolder(mBinding.viewPage.findFocus())
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (viewHolder != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (viewHolder.layoutPosition !=<span style="color: rgba(0, 0, 0, 1)"> RecyclerView.NO_POSITION) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使其翻页</span>
mBinding.viewPage.currentItem =<span style="color: rgba(0, 0, 0, 1)"> viewHolder.layoutPosition
}
}
}
}
}
}
}</span></pre>
</div>
<p> </p>
<h1><span style="background-color: rgba(255, 255, 255, 1)"><span style="color: rgba(0, 128, 128, 1)">ViewPager2的已知bug</span></span></h1>
<p> 因为ViewPager与SwipeRefreshLayout冲突导致RecyclerView或者其他列表布局的item无法点击的问题</p>
<p> </p>
<p>End</p>
</div>
<div id="MySignature" role="contentinfo">
<div style="text-align: center">
<p style="color:orange;font-size:16px;" >本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/13528962.html </p>
<div style="color:orange;font-size:16px;">本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。 </div>
</div><br><br>
来源:https://www.cnblogs.com/guanxinjing/p/13528962.html
頁:
[1]