1.先添加一下anko

依赖:implementation "org.jetbrains.anko:anko:$anko_version"

版本:ext.anko_version='0.10.8'

2.新建Activity和Fragment的两个基类,方便以后使用

abstract class BaseActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(getLayoutId())
initData();
onListener();
} abstract fun getLayoutId(): Int;//继承此类必须先实现此方法 protected open fun initData(){ } protected open fun onListener() { }

//

abstract class BaseFragment:Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initData()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return initView();
} override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
onListener()
} abstract fun initView():View? protected open fun initData(){ } protected open fun onListener(){ }
}
3.底部导航
方案一:bottombar
依赖:implementation 'com.roughike:bottom-bar:2.3.1'
activity_main.xml改成LinearLayout布局,设置垂直布局
<FrameLayout
android:id="@+id/contentContainer"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"/> <com.roughike.bottombar.BottomBar
android:id="@+id/bottomBar"
android:layout_width="match_parent"
android:layout_height="56dp"
app:bb_tabXmlResource="@xml/bottombar_tabs"/>
新建xml Directory,添加bottombar_tabs.xml
<?xml version="1.0" encoding="utf-8"?>
<tabs>
<tab
id="@+id/tab_homepage"
icon="@drawable/homepage_icon"
title="主页" />
<tab
id="@+id/tab_favorites"
icon="@drawable/favorites_icon"
title="收藏" />
<tab
id="@+id/tab_message"
icon="@drawable/message_icon"
title="消息" />
<tab
id="@+id/tab_personal"
icon="@drawable/personal_icon"
title="我的" />
</tabs>
添加图标资源到drawable-xxhdpi目录中(不能直接添加到drawable中)
添加监听很简单
    override fun initData() {
bottomBar.setOnTabSelectListener{
//it即是tab的id
// println(it)
}
接下来准备点击切换的四个fragment,都继承自BaseFragment,例如
class FavoritesFragment:BaseFragment() {

    override fun initView(): View? {
var textView:TextView=TextView(activity) //getActivity()返回与之关联的activity
textView.text="收藏"
return textView
}
}
再准备一个管理fragment的类FragmentManage
class FragmentManage {
fun getFragment(tab_id:Int):BaseFragment?{
when(tab_id){
R.id.tab_homepage->return HomePageFragment()
R.id.tab_favorites->return FavoritesFragment()
R.id.tab_message->return MessageFragment()
R.id.tab_personal->return Personal()
}
return null
}
}
优化后的代码,创建单例模式,采用懒加载定义变量
class FragmentManage private constructor(){
val homePageFragmeng by lazy{HomePageFragment()}
val favoritesFragment by lazy{FavoritesFragment()}
val messageFragment by lazy{MessageFragment()}
val PersonalFragment by lazy{Personal()} companion object{
val fragmentManage by lazy{
FragmentManage()
}
}
fun getFragment(tab_id:Int):BaseFragment?{
when(tab_id){
R.id.tab_homepage->return homePageFragmeng
R.id.tab_favorites->return favoritesFragment
R.id.tab_message->return messageFragment
R.id.tab_personal->return PersonalFragment
}
return null
}
}
这里可能找不到id,重启一下就可以了。R资源路径app\build\generated\not_namespaced_r_class_sources\debug\r\com\vocus\justtest
在MainActivity中设置对bottomBar的监听,并动态添加fragment
override fun initData() {
bottomBar.setOnTabSelectListener {
//it即是tab的id
// println(it)
val transAction = supportFragmentManager.beginTransaction()
//transAction.replace(R.id.contentContainer,FragmentManage().getFragment(it) as BaseFragment, it.toString())
transAction.replace(R.id.contentContainer,FragmentManage.fragmentManage.getFragment(it)!!,it.toString())
transAction.commit() }
}
 
效果:
 

 方案二:BottomNavigationView
null
4.主界面,设置HomePageFragment
设置状态栏背景透明
null
广告图片轮播(ViewPager)
设置homepagefragment布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager.widget.ViewPager
android:id="@+id/vp_homePageAd"
android:layout_width="match_parent"
android:layout_height="300dp">
</androidx.viewpager.widget.ViewPager> <LinearLayout
android:id="@+id/dot_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_centerHorizontal="true"
android:layout_alignBottom="@+id/vp_homePageAd"
android:layout_marginBottom="10dp"> </LinearLayout> </RelativeLayout>
新建HomePageAdAdapter类
class HomePageAdAdapter(): PagerAdapter(){
private val imageViewList=ArrayList<ImageView>()
constructor(imageViewList:ArrayList<ImageView>):this(){
this.imageViewList.addAll(imageViewList)
} override fun isViewFromObject(view: View, `object`: Any): Boolean {
return view==`object`
} override fun instantiateItem(container: ViewGroup, position: Int): Any {
// var textView= TextView(container.context)
// textView.text="test"
// container.addView(textView)
// return textView
container.addView(imageViewList.get(position))
return imageViewList.get(position)
} override fun getCount(): Int {
return imageViewList.size
} override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
container.removeView(`object` as View)
}
}
在HomePageFragment中添加代码
  • 重写onListener方法(在onActivityCreated的生命周期里)
  • 定义资源

 var imagesId=listOf(R.drawable.pic1,R.drawable.pic2,R.drawable.pic3,R.drawable.pic4,R.drawable.pic5)

        //定义五个图片控件,用于加载图片资源
var imageViewList=ArrayList<ImageView>()
for(i in 0 until 5){
var imageView:ImageView=ImageView(activity)
imageView.setImageResource(imagesId[i])
imageViewList.add(imageView) }
 
  • 添加监听
//        var vp_homePage:ViewPager=view!!.findViewById(R.id.vp_homePageAd)
// vp_homePage.adapter=HomePageAdAdapter()
vp_homePageAd.adapter=HomePageAdAdapter(imageViewList) // //添加页面改变监听
vp_homePageAd.addOnPageChangeListener(object :ViewPager.OnPageChangeListener{
override fun onPageScrollStateChanged(state: Int) { } //页面滚动的时候
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) { } override fun onPageSelected(position: Int) {
//添加圆点导航
addDots(position)
} }) }
  • 增加圆点导航方法
//偷懒的方法
fun addDots(position:Int){

        dot_container.removeAllViews()
var dots=arrayOf<TextView>(TextView(activity),TextView(activity),TextView(activity),TextView(activity),TextView(activity))
dots.forEach {
it.text="."
it.setTextColor(Color.GRAY)
it.textSize=30f
} for(i in 0 until 5) {
dot_container.addView(dots[i])
}
dots[position].setTextColor(Color.WHITE) }
The specified child already has a parent. You must call removeView() on the child's parent first
我在把同一个TextView多次添加到布局中发生此错误,因为添加一次之后TextView就有parent了,直接在for循环中使用(textView.parent as ViewGroup?)!!.removeView(textView)也不行,因为循环的第二次会把第一次添加的移除。所以只能创建多个textview
错误代码为:
fun addDots(position:Int){
var dots=ArrayList<TextView>()
var textView=TextView(context)
textView.text="."
textView.setTextColor(Color.RED)
textView.textSize=30f for(i in 0 until 5) {
if ((textView.parent as ViewGroup?) != null) {
(textView.parent as ViewGroup?)!!.removeView(textView)
}
dot_container.addView(textView)
}
}

继续完善

  • 增加无限翻页
将getCount()返回值设置为Integer.MAX_VALUE,资源列表用到position取值的地方,要按5取模position%5,这样可以实现向后无限翻页;为了保证向前也能无限翻页,将PagerView的当前页设置为Integer.MAX_VALUE/2,同时-Integer.MAX_VALUE/2%5保证为5的倍数
vp_homePageAd.currentItem=Integer.MAX_VALUE/2-Integer.MAX_VALUE/2%5
  • 循环播放
val handler: Handler =object:Handler(){
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
vp_homePageAd.currentItem+=1 sendEmptyMessageDelayed(0,4000)
} }
调用:handler.sendEmptyMessageDelayed(0,4000)
var flag:Int?=null
vp_homePageAd.setOnTouchListener(object:View.OnTouchListener{
override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
//Toast.makeText(context,"-x:${p1.x},y:${p1.y}",Toast.LENGTH_SHORT).show(); when(p1!!.action){
MotionEvent.ACTION_DOWN->flag=0
//MotionEvent.ACTION_UP->flag=1
MotionEvent.ACTION_MOVE->flag=2
}
println(flag.toString())
if(p1!!.action==MotionEvent.ACTION_UP&& flag==0){
val currentPage=vp_homePageAd.currentItem%5
when(currentPage+1){
1->Toast.makeText(context,"1",Toast.LENGTH_SHORT).show()
2->Toast.makeText(context,"2",Toast.LENGTH_SHORT).show()
3->Toast.makeText(context,"3",Toast.LENGTH_SHORT).show()
4->Toast.makeText(context,"4",Toast.LENGTH_SHORT).show()
5->Toast.makeText(context,"5",Toast.LENGTH_SHORT).show() }
}
return false
}

(每次响应点击事件都会调用这个函数,比如按下,松开会调用两次该函数,所以flag应该是个全局变量)

  •  其他未实现
·可以给每个页面添加文字说明
·用户按住某个页面时,应该停止轮播
 效果

源码:

链接:https://pan.baidu.com/s/1zx5IXnD74ySe_bYM9F17xQ
提取码:hmg5

问题补充:

第一次进去程序没有圆点导航,需要初始化一下

Handler函数中调用vp_homePageAd加一个非空判断,因为切换底部导航tab的时候,vp_homePageAd变为空

												

尝试用kotlin做一个app(一)的更多相关文章

  1. 尝试用kotlin做一个app(写在前面)

    学kotlin的目的好像就是做一个app,不一定有什么想做的项目,只是单纯想掌握这一门技术,确切地说只是单纯想学会做app.对于概念的东西,我也没兴趣深究,用得到的学一下,用不到的,就算了.我也不知道 ...

  2. 尝试用kotlin做一个app(二)

    导航条 我想实现的效果是这样的 类似于ViewPager的效果,子类导航页面可以滑动,当滑动某个子类导航页面,导航线会平滑地向父类导航移动 ·添加布局 <!--导航分类:编程语言/技术文档/源码 ...

  3. 尝试用kotlin做一个app(五)

    JSP后台管理系统 开发工具是IntelliJ IDEA+tomcat+mysql5.6.19+mysql-connector-java-5.1.48.jar+easyui+kindeditor 之前 ...

  4. 尝试用kotlin做一个app(四)

    本来是应该为主页加载数据库数据了,但是想着做后台,之前写jsp后台写吐了,所以先拖几天.把之前的代码完善一下,或者添加些新内容. ...... 多个fragment切换卡顿 首先修正一个bug.从主页 ...

  5. 尝试用kotlin做一个app(三)

    新闻列表 添加新闻列表可以使用RecyclerView.但是有个问题,RecyclerView只会在内部滚动,不会带动整个屏幕滚动.所以在原根布局外层添加androidx.core.widget.Ne ...

  6. 做一个 App 前需要考虑的几件事

    做一个 App 前需要考虑的几件事  来源:limboy的博客   随着工具链的完善,语言的升级以及各种优质教程的涌现,做一个 App 的成本也越来越低了.尽管如此,有些事情最好前期就做起来,避免当 ...

  7. 做一个App前需要考虑的几件事

    本文转载于文章原文链接,版本归原作者所有! 随着工具链的完善,语言的升级以及各种优质教程的涌现,做一个 App 的成本也越来越低了.尽管如此,有些事情最好前期就做起来,避免当 App 有了一定规模后, ...

  8. 涨姿势:创业做一个App需要花多少钱(8个人,6个月,就要100万,附笔记心得)

    (原标题:涨姿势:创业做一个App要花多少钱?) 作为互联网从业者,被外行的朋友们问及最多的问题是,“做一个网站需要多少钱?”或者“做一个APP需要多少钱?”. 作为做过完整网站项目和APP的人,今天 ...

  9. [转载]做一个 App 前需要考虑的几件事

    本文转自http://limboy.me/tech/2016/07/06/starting-an-app.html ========================================= ...

随机推荐

  1. java多线程(待完善)

    1.小型系统 // 线程完成的任务(Runnable对象)和线程对象(Thread)之间紧密相连 class A implements Runnable{ public void run(){ // ...

  2. 蓝牙 BLE 协议学习: 000-有关概念介绍

    背景 在学校内就用过蓝牙技术参加过比赛(并拿了奖):而蓝牙作为物联网中比较常见的协议,有必要进行深入的学习.此后的文章会以 ble(v4.0) 进行学习. 介绍 蓝牙技术最初由电信巨头爱立信公司于 1 ...

  3. 在ListView头和尾添加东西

    直接上代码 import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view ...

  4. 定时执行 Job【转】

    Linux 中有 cron 程序定时执行任务,Kubernetes 的 CronJob 提供了类似的功能,可以定时执行 Job.CronJob 配置文件示例如下: ① batch/v2alpha1 是 ...

  5. ROS常用库(五)navigation之Tutorials

    一.TF 详见古月居 https://www.guyuehome.com/355 重点:广播TF,订阅,编译时Cmakelist添加编译选项 broadcaster.sendTransform( tf ...

  6. C++编程学习(十二) STL

    一.简介 标准模板库STL,是一组模板类和函数.提供了: 1.容器.用于存储信息. 2.迭代器.用于访问容器中的信息. 3.算法.操作容器内容. 1.容器 STL有两种类型的容器类: (1)顺序容器 ...

  7. Springboot注解使用总结

    使用Spring boot已经有段时间了,但是对很多注解的使用经常会遇到模糊甚至不解的地方,这次有时间便总结一下. 注解(Annotation)概念 注解是Java5开始对元数据的支持,注解与注释是有 ...

  8. 前端构建工具gulp超详细配置, 使用教程(图文)

    流程 1. 输入命令(可以使用git bash或者命令控制台cmd) npm install -g gulp 安装全局gulp命令 2. 创建一个项目文件夹, 当前项目文件夹下输入命令npm init ...

  9. redis数据导入与导出以及配置使用

    最近在研究redis 遇到redis requires Ruby version >= 2.2.2问题 解决办法是 先安装rvm,再把ruby版本提升至2.3.3 1.安装curl sudo y ...

  10. Irecycleview 的初次使用简单介绍(irecycleview 下拉刷新上拉加载)

    导包 还得加一个maven地址自己也看一下作者git把有详细解释(自己也要导入recycleview的包) 我的例子下载地址  https://www.lanzous.com/i32yzaj impl ...