嘗試用kotlin做一個app(一)


1.先添加一下anko庫,添加庫之后,右上角提示,sync now...點擊即可

依賴: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布局,設置垂直布局,並設置android:orientation="vertical"
 
        
<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>

 在HomepageFragment中引入布局

 

class HomeFragment: BaseFragment(){
    override fun initView(): View? {
        return View.inflate(activity, R.layout.fragment_home,null)
    }
}

 

新建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應該是個全局變量)

  •  其他
·可以給每個頁面添加文字說明
這個跟添加原點導航差不多,
·用戶按住某個頁面時,應該停止輪播
可以增加一個isLoop的布爾值變量,在ViewPager觸摸監聽中,按下的時候,設置isLoop=false,放開的時候設置isLoop=true;同時在handleMessage中判斷,當isLoop為true時,才發送消息。
val handler:android.os.Handler=object :android.os.Handler(){
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            println("handler:"+isLoop)
            if(isLoop) {
                if(vp_home_ad!=null){
                    vp_home_ad.currentItem += 1
                }
                //
            }
            sendEmptyMessageDelayed(0, 4000)//不管isLoop是真假,都間隔4s發送一次消息,只是當為假的時候,不跳頁
} }
 
        
 效果


源碼:
https://files.cnblogs.com/files/vocus/kotlin_app_1.zip

鏈接:https://pan.baidu.com/s/1zx5IXnD74ySe_bYM9F17xQ
提取碼:hmg5

 

問題補充:

第一次進去程序沒有圓點導航,需要初始化一下,即事先調用一次addDots函數

 

Handler函數中調用vp_homePageAd加一個非空判斷,因為切換底部導航tab的時候,vp_homePageAd變為空

 
        

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM