使用Kotlin实现UC头条ViewPager左右滑动效果
转载请标明出处:一片枫叶的专栏
上一篇文章中我们讲解了一个使用的多行文本显示控件,在实际开发过程中我们时常会遇到这种需求:有两个TextView控件分行显示,当第一个TextView的内容过多一行显示不下时,我们需要将第二个TextView在第一个TextView的第二行末尾显示,当第二个TextView第二行也显示不下时,第一个TextView的第二行结尾以“…”结束,第二个TextView显示在第二行的最后段,而上一篇文章介绍的就是一个实现这种需求的自定义控件。
而本文我们将介绍一个使用kotlin实现的仿照UC头条ViewPager的左右滑动效果。这个项目是为了学习kotlin的使用以及基本语法,在实现的过程中主要需要注意的有两点:一个是UC头条在滑动过程中的遮盖动画效果,一个是跨多个Tab点击屏蔽多个页面滑动效果。
本项目的github地址:android-xmviewpager,欢迎star和follow。
在介绍具体的使用说明之前,我们先看一下简单的实现效果:
实现说明
本项目是通过TabLayout+ViewPager的方式实现的,这里我们首先看一下整个页面的布局文件的实现方式:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".java.TabLayoutActivity"android:orientation="vertical"><android.support.design.widget.AppBarLayoutandroid:id="@+id/appbar"android:layout_width="match_parent"android:layout_height="wrap_content"android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"><android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"app:layout_scrollFlags="scroll|enterAlways"app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/><android.support.design.widget.TabLayoutandroid:id="@+id/tabs"android:layout_width="match_parent"android:layout_height="wrap_content"app:tabIndicatorColor="#ADBE107E"app:tabIndicatorHeight="0dp"app:tabMode="scrollable"app:tabPadding="0dp"/></android.support.design.widget.AppBarLayout><android.support.v4.view.ViewPagerandroid:id="@+id/viewpager"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="@string/appbar_scrolling_view_behavior"/></LinearLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
![](http://static.blog.csdn.net/images/save_snippets.png)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
可以发现其是通过TabLayout和ViewPager的方式实现的,在实现过程中由于要求点击跨多个Tab的时候屏蔽多次滑动效果,这里重写了TabLayout的onTabSelectedListener监听:
/*** 自定义函数, : Unit 表示函数没有返回值*/fun initViewPager() : Unit {/*** 获取初始化数据*/val titles = ViewData().getTitles()/*** as 类似于java中的类型强转*/val toolbar = findViewById(R.id.toolbar) as ToolbarsetSupportActionBar(toolbar)mViewPager = findViewById(R.id.viewpager) as ViewPagermTabLayout = findViewById(R.id.tabs) as TabLayout/*** 通过 in 关键字实现循环遍历* 在调用mTabLayou变量的方法时,由于mTabLayout可能为空,所以在调用方法时添加!!* titles[] 与 titles.get 方法的功能是一样的* titles.indices 获取的是数组的下标*/for (i in titles.indices) {mTabLayout!!.addTab(mTabLayout!!.newTab().setText(titles[i]))}val fragments = ArrayList<Fragment>()/*** 循环遍历添加ViewPager的Fragment*/for (i in titles.indices) {val listFragment = MListFragment()val bundle = Bundle()val sb = StringBuffer()for (j in 1..8) {sb.append(titles[i]).append(" ")}bundle.putString("content", sb.toString())listFragment.arguments = bundlefragments.add(listFragment)}val mFragmentAdapteradapter = MFragmentAdapter(supportFragmentManager, fragments, titles)mViewPager!!.adapter = mFragmentAdapteradaptermViewPager!!.adapter = mFragmentAdapteradaptermTabLayout!!.setupWithViewPager(mViewPager)mTabLayout!!.setTabsFromPagerAdapter(mFragmentAdapteradapter)/*** 自定义设置ViewPager切换动画*/mViewPager!!.setPageTransformer(true, MTransformer())/*** 通过object : TabLayout.OnTabSelectedListener 的方式创建内部匿名类(这里主要是接口)*/mTabLayout!!.setOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {override fun onTabReselected(tab: TabLayout.Tab?) {}override fun onTabUnselected(tab: TabLayout.Tab?) {}override fun onTabSelected(tab: TabLayout.Tab?) {/*** 控制变量*/if (isOk) {isOk = falseval currentItemIndex = mViewPager!!.currentItemif (Math.abs(currentItemIndex - tab!!.position) > 1) {/*** 向后点击*/if (currentItemIndex <= tab!!.position) {mViewPager!!.setCurrentItem(tab.position - 1, false)mViewPager!!.setCurrentItem(tab.position, true)}/*** 向前点击*/else {mViewPager!!.setCurrentItem(tab.position + 1, false)mViewPager!!.setCurrentItem(tab.position, true)}} else {mViewPager!!.setCurrentItem(tab.position, true)}isOk = true}}})}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
![](http://static.blog.csdn.net/images/save_snippets.png)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
然后我们可以继续看一下初始化数据的实现:
/*** Created by aaron on 16/9/14.* 主要用于保存界面ViewPager数据*/
class ViewData {/*** 该方法用于获取ViewPager TAB 显示数据*/fun getTitles() : ArrayList<String> {/*** 通过类名创建该类的对象,这里直接调用java中的集合框架*/val titles = ArrayList<String>()titles.clear()titles.add("推荐")titles.add("视频")titles.add("热点")titles.add("娱乐")titles.add("体育")titles.add("北京")titles.add("财经")titles.add("科技")titles.add("汽车")titles.add("社会")titles.add("搞笑")titles.add("军事")titles.add("历史")titles.add("涨知识")titles.add("NBA")titles.add("两性")return titles}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
![](http://static.blog.csdn.net/images/save_snippets.png)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
好吧,这其中需要注意的是:viewPager的setCurrentItem方法,表示会将viewPager的当前显示Item设置为指定的item,而我们可以发现这里的setCurrentItem有两个参数,第一个参数,是显示当前Item的position,而第二个参数为boolean类型,表示是否有滑动效果,比如当前我们在ViewPager的第一项,而我们点击了TabLayout的第八项,这时候如果我们调用了:setCurrentItem(8, true),它表示我们将滑动到ViewPager的第八项,且有滚动效果。这样我们做一下变通,当我们点击的TabLayout与当前Item的距离大于一个Item的时候就先滑动到当前Item的前一个并且没有滑动效果,然后在执行一次setCurrentItem方法,这样在跨多个Tab点击的时候就屏蔽了多个Item滚动的效果了。
在实现过程中还需要实现滑动覆盖的效果,一开始想了很久包括使用ViewPager的setPageTransformer方法,但是还是没法实现这个思路,后来经过同事指点,终于搞定了。就是对ViewPager每一项item中的子View执行动画效果,这样就会实现需求的动画效果了。
以下是自己重写的setPageTransformer类:
/*** Created by aaron on 16/9/13.* 自定义实现ViewPager的切换动画效果*/
class MTransformer : ViewPager.PageTransformer {/*** 回调方法,重写viewpager的切换动画*/override fun transformPage(view: View, position: Float) {val pageWidth = view.widthval wallpaper = view.findViewById(R.id.recycler_view)if (position < -1) { // [-Infinity,-1)wallpaper.translationX = 0.toFloat()view.translationX = 0.toFloat()} else if (position <= 1) { // [-1,1]wallpaper.translationX = pageWidth * getFactor(position)view.translationX = 8 * position} else { // (1,+Infinity]wallpaper.translationX = 0.toFloat()view.translationX = 0.toFloat()}}private fun getFactor(position: Float): Float {return -position / 2}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
![](http://static.blog.csdn.net/images/save_snippets.png)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
可以看到在我们自定义的PageTransformer中,我们通过findViewById方法获取了滑动Item的子View,并对子View执行translationX操作,进而实现了滑动Item的遮盖效果。
另外由于本文主要介绍Kotlin的使用,更多关于Kotlin的相关知识点,可参考:
Basic Syntax - Kotlin Programing
Kotlin:Android事件的Swift
Kotlin在Android工程中的应用
当然更具体的关于本控件的实现可以下载源码参考。
总结:
以上就是通过Kotlin实现的仿照UC头条ViewPager左右滑动效果的小项目。当然现在还很不完善,对于源码有兴趣的同学可以到github上看一下具体实现。项目地址:android-xmviewpager
另外对github项目,开源项目解析感兴趣的同学可以参考我的:
Github项目解析(一)–>上传Android项目至github
Github项目解析(二)–>将Android项目发布至JCenter代码库
Github项目解析(三)–>Android内存泄露监测之leakcanary
Github项目解析(四)–>动态更改TextView的字体大小
Github项目解析(五)–>Android日志框架
Github项目解析(六)–>自定义实现ButterKnife框架
Github项目解析(七)–>防止按钮重复点击
Github项目解析(八)–>Activity启动过程中获取组件宽高的五种方式
Github项目解析(九)–>实现Activity跳转动画的五种方式
Github项目解析(十)–>几行代码快速集成二维码扫描库
Github项目解析(十一)–>一个简单,强大的自定义广告活动弹窗
Github项目解析(十二)–>一个简单的多行文本显示控件
(function () {(function () {('pre.prettyprint code').each(function () { var lines = (this).text().split(′\n′).length;var(this).text().split('\n').length;var numbering = $('').addClass('pre-numbering').hide(); (this).addClass(′has−numbering′).parent().append((this).addClass('has-numbering').parent().append(numbering); for (i = 1; i
使用Kotlin实现UC头条ViewPager左右滑动效果相关推荐
- 自定义ViewGroup实现ViewPager的滑动效果
看下他的 布局 文件: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout andr ...
- 禁用ViewPager边界滑动效果(转)
反射设置方法 1 private EdgeEffectCompat leftEdge; 2 private EdgeEffectCompat rightEdge; 3 public void Disa ...
- ViewPager之使用PagerTabStrip添加标题栏,实现滑动效果
1.首先,转自: (1).<ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同> 这篇文章写得不错,大家可以参考一下. (2). ...
- android 打造炫酷导航栏(仿UC头条)
年后开始上班甚是清闲,所以想捣鼓一些东西.在翻阅大神杰作Android 教你打造炫酷的ViewPagerIndicator 不仅仅是高仿MIUI 的时候看到下面有一条评论说,如果导航栏能滑动就更好了. ...
- UC浏览器主界面滑动折叠效果 使用自定义behavior实现 难度五颗星*****
思路:!!!!!!!!!!! RcycleView上的HeadScrollBehavior 思路: 1.让recycleview居于头部的下方 ---方案: 重写layoutDependsOn 让当 ...
- SwipeRefreshLayout源码分析+自定义UC头条下拉刷新Demo
首先来看SwipeRefreshLayout(以下简称SR)的继承关系 NestedScrollingParent:嵌套滑动父接口 NestedScrollingChild :嵌套滑动子接口 Andr ...
- Android WebView与ViewPager的滑动冲突分析
前言 如题所述,我使用的架构是ViewPager+Fragment+WebView进行开发的,由于WebView的html页面代码是第三方的,这里不好放出来,所以只能放一个大致的架构图,如图所示,Vi ...
- android ViewPager 不带滑动效果切换item
其实这是很简单的,但是今晚脑袋晕乎乎的 绕了一大圈,记录一下 以警同类人. 只需要在setCurrentItem传参数时这么写:mViewPager.setCurrentItem(item序号,fal ...
- ViewPager相互嵌套,导致子ViewPager无法滑动,且子ViewPager中的view无法被点击
场景:当使用ViewPager进行嵌套的时候,子viewPager是无法进行嵌套的,因此我们要重写ViewPager类,并重写里层viewPager类中的onTouchEvent方法,调用其父 ...
最新文章
- Java的SPI机制
- 第十三届光华工程科技奖公布,彭士禄、张伯礼、王海峰等40人及1个团体获奖
- 随机模拟【1】:随机模拟的研究范围与特征
- ML之DT之CART:分类与回归树CART算法的简介、应用、经典案例之详细攻略
- 给ButtonBar组件设置自定义TOOLTIP。
- linux 漏洞数量,Debian Linux被列为过去20年漏洞数量最多的操作系统
- mtk android 5.1 logo,Android ROM DIY之MTK平台手机通用移植
- python脚本运行命令_从Python脚本运行shell命令
- 一部影响美国网络安全政策的电影
- Apache Flink 1.9.0 为什么将支持 Python API ?
- Redis(RedisTemplate)使用hash哈希
- 你会用 JSON.stringify()? JSON.stringify一些坑
- python简单编程--ATM银行管理系统
- 笔记-软考高项-错题笔记汇总4
- 如何区分冲突域和广播域?
- 这些书你读过一多半,你就是编程大牛!
- 【免费】各种hadoop版本对应的hadoop.dll和winutils.exe
- Python中的shuffle()函数
- 如何用OpenCV改变图片的大小?
- 【Hibernate步步为营】--映射合集汇总