今天看啥  ›  专栏  ›  客观开发者

完整app -- Eyepetizer 学习

客观开发者  · 简书  ·  · 2021-04-20 14:35

最近看的一个Eyepetizer 的项目挺好的。学习如下
源码地址: https://www.jianshu.com/p/bb1b45eebecc

1,自定义 字体

  class TypefaceTextView : AppCompatTextView {

constructor(context: Context) : this(context, null)

constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
    attrs?.let {
        val typedArray = context.obtainStyledAttributes(it, R.styleable.TypefaceTextView, 0, 0)
        val typefaceType = typedArray.getInt(R.styleable.TypefaceTextView_typeface, 0)
        typeface = getTypeface(typefaceType)
        typedArray.recycle()
    }
}

companion object {

    /**
     * 根据字体类型,获取自定义字体。
     */
    fun getTypeface(typefaceType: Int?) = when (typefaceType) {
        TypeFaceUtil.FZLL_TYPEFACE -> TypeFaceUtil.getFzlLTypeface()
        TypeFaceUtil.FZDB1_TYPEFACE -> TypeFaceUtil.getFzdb1Typeface()
        TypeFaceUtil.FUTURA_TYPEFACE -> TypeFaceUtil.getFuturaTypeface()
        TypeFaceUtil.DIN_TYPEFACE -> TypeFaceUtil.getDinTypeface()
        TypeFaceUtil.LOBSTER_TYPEFACE -> TypeFaceUtil.getLobsterTypeface()
        else -> Typeface.DEFAULT
    }
}

}
TypeFaceUtil 内容

const val FZLL_TYPEFACE = 1

const val FZDB1_TYPEFACE = 2

const val FUTURA_TYPEFACE = 3

const val DIN_TYPEFACE = 4

const val LOBSTER_TYPEFACE = 5

private var fzlLTypeface: Typeface? = null

private var fzdb1Typeface: Typeface? = null

private var futuraTypeface: Typeface? = null

private var dinTypeface: Typeface? = null

private var lobsterTypeface: Typeface? = null

fun getFzlLTypeface() = if (fzlLTypeface == null) {
    try {
        Typeface.createFromAsset(EyepetizerApplication.context.assets, "fonts/FZLanTingHeiS-L-GB-Regular.TTF")
    } catch (e: RuntimeException) {
        Typeface.DEFAULT
    }
} else {
    fzlLTypeface!!
}

fun getFzdb1Typeface() = if (fzdb1Typeface == null) {
    try {
        Typeface.createFromAsset(EyepetizerApplication.context.assets, "fonts/FZLanTingHeiS-DB1-GB-Regular.TTF")
    } catch (e: RuntimeException) {
        Typeface.DEFAULT
    }
} else {
    fzdb1Typeface!!
}

fun getFuturaTypeface() = if (futuraTypeface == null) {
    try {
        Typeface.createFromAsset(EyepetizerApplication.context.assets, "fonts/Futura-CondensedMedium.ttf")
    } catch (e: RuntimeException) {
        Typeface.DEFAULT
    }
} else {
    futuraTypeface!!
}

fun getDinTypeface() = if (dinTypeface == null) {
    try {
        Typeface.createFromAsset(EyepetizerApplication.context.assets, "fonts/DIN-Condensed-Bold.ttf")
    } catch (e: RuntimeException) {
        Typeface.DEFAULT
    }

} else {
    dinTypeface!!
}

fun getLobsterTypeface() = if (lobsterTypeface == null) {
    try {
        Typeface.createFromAsset(EyepetizerApplication.context.assets, "fonts/Lobster-1.4.otf")
    } catch (e: RuntimeException) {
        Typeface.DEFAULT
    }

} else {
    lobsterTypeface!!
}
   <declare-styleable name="TypefaceTextView">
        <attr name="typeface">
            <enum name="fzlLTypeface" value="1" />
            <enum name="fzdb1Typeface" value="2" />
            <enum name="futuraTypeface" value="3" />
            <enum name="dinTypeface" value="4" />
            <enum name="lobsterTypeface" value="5" />
        </attr>
    </declare-styleable>
fonts/fonts 放入字体

使用

 <com.eyepetizer.android.ui.common.view.TypefaceTextView
            android:id="@+id/tvTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/ivAvatar"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="18dp"
            android:layout_marginBottom="50dp"
            android:text="@string/guide_login_tips_four"
            android:textColor="@color/grayDark"
            android:textSize="12sp"
            app:typeface="fzlLTypeface" />

2,颜色 收集

    <color name="white">#ffffff</color>
    <color name="whiteAlpha85">#26ffffff</color>
    <color name="whiteAlpha80">#33ffffff</color>
    <color name="whiteAlpha60">#66ffffff</color>
    <color name="whiteAlpha50">#80ffffff</color>
    <color name="whiteAlpha35">#a6ffffff</color>
    <color name="whiteAlpha25">#bfffffff</color>
    <color name="whiteAlpha20">#ccffffff</color>
    <color name="whiteAlpha10">#e6ffffff</color>
    <color name="blackAlpha95">#0d000000</color>
    <color name="blackAlpha85">#26000000</color>
    <color name="blackAlpha80">#33000000</color>
    <color name="blackAlpha70">#4d000000</color>
    <color name="blackAlpha60">#66000000</color>
    <color name="blackAlpha55">#73000000</color>
    <color name="blackAlpha50">#80000000</color>
    <color name="blackAlpha45">#8c000000</color>
    <color name="blackAlpha20">#cc000000</color>
    <color name="black">#000000</color>
  1. 友盟统计的使用

下载
https://developer.umeng.com/sdk/android
UMConfigure.init(this, null, null, UMConfigure.DEVICE_TYPE_PHONE, null)
UMConfigure.setLogEnabled(BuildConfig.DEBUG)
<meta-data
android:name="UMENG_APPKEY"
android:value="5ee21dfcdbc2ec078743b1f3" />
<meta-data
android:name="UMENG_CHANNEL"
android:value="opensource" />

4,de8错误使用
MultiDex.install(this)

5,leakcanary 的使用
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'

使用

6.PermissionX 权限的使用
implementation 'com.android.support:multidex:1.0.3'
主要好是内置了dialog 取消和 同意


    private fun requestWriteExternalStoragePermission() {
        PermissionX.init(this@SplashActivity).permissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
            .onExplainRequestReason { scope, deniedList ->
                val message = GlobalUtil.getString(R.string.request_permission_picture_processing)
                scope.showRequestReasonDialog(deniedList, message, GlobalUtil.getString(R.string.ok), GlobalUtil.getString(R.string.cancel))
            }
            .onForwardToSettings { scope, deniedList ->
                val message = GlobalUtil.getString(R.string.request_permission_picture_processing)
                scope.showForwardToSettingsDialog(deniedList, message, GlobalUtil.getString(R.string.settings), GlobalUtil.getString(R.string.cancel))
            }
            .request { allGranted, grantedList, deniedList ->
                requestReadPhoneStatePermission()
            }
    }

    private fun requestReadPhoneStatePermission() {
        PermissionX.init(this@SplashActivity).permissions(Manifest.permission.READ_PHONE_STATE)
            .onExplainRequestReason { scope, deniedList ->
                val message = GlobalUtil.getString(R.string.request_permission_access_phone_info)
                scope.showRequestReasonDialog(deniedList, message, GlobalUtil.getString(R.string.ok), GlobalUtil.getString(R.string.cancel))
            }
            .onForwardToSettings { scope, deniedList ->
                val message = GlobalUtil.getString(R.string.request_permission_access_phone_info)
                scope.showForwardToSettingsDialog(deniedList, message, GlobalUtil.getString(R.string.settings), GlobalUtil.getString(R.string.cancel))
            }
            .request { allGranted, grantedList, deniedList ->
                setContentView(R.layout.activity_splash)
            }
    }

7.refresh 下拉刷新和上拉更多的使用
implementation 'com.scwang.smart:refresh-header-material:2.0.0'
implementation 'com.scwang.smart:refresh-layout-kernel:2.0.0'

最新版本更新。额尽量使用最新的。好像包名都修改了。

在application 中配置

 init {
        SmartRefreshLayout.setDefaultRefreshInitializer { context, layout ->
            layout.setEnableLoadMore(true)
            layout.setEnableLoadMoreWhenContentNotFull(true)
        }

        SmartRefreshLayout.setDefaultRefreshHeaderCreator { context, layout ->
            layout.setEnableHeaderTranslationContent(true)
            MaterialHeader(context).setColorSchemeResources(R.color.blue, R.color.blue, R.color.blue)
        }

        SmartRefreshLayout.setDefaultRefreshFooterCreator { context, layout ->
            layout.setEnableFooterFollowWhenNoMoreData(true)
            layout.setEnableFooterTranslationContent(true)
            layout.setFooterHeight(153f)
            layout.setFooterTriggerRate(0.6f)
            NoStatusFooter.REFRESH_FOOTER_NOTHING = "- The End -"
            NoStatusFooter(context).apply {
                setAccentColorId(R.color.colorTextPrimary)
                setTextTitleSize(16f)
            }
        }
    }

java 中使用 请用static{}

  1. kotlin 携程的使用
    private val job by lazy { Job() }
GlobalScope.launch(Dispatchers.Main) {}
//替换下面
 CoroutineScope(job).launch {
            delay(splashDuration)
            MainActivity.start(this@SplashActivity)
            finish()
        }
 
  override fun onDestroy() {
        super.onDestroy()
        job.cancel()
    }

携程里面好多,可以搜索一下。

9.动画的使用。。原来也可以用lazy 来做。

    private val alphaAnimation by lazy {
        AlphaAnimation(0.5f, 1.0f).apply {
            duration = splashDuration
            fillAfter = true
        }
    }

    private val scaleAnimation by lazy {
        ScaleAnimation(1f, 1.05f, 1f, 1.05f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f).apply {
            duration = splashDuration
            fillAfter = true
        }
    }

10 constraintlayout 里面的方法的使用。。
主要是里面就几个方法,居然自己还不好用。。。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="42dp"
    android:background="@color/colorPrimary"
    android:paddingLeft="24dp"
    android:paddingRight="24dp">

    <ImageView
        android:id="@+id/ivHomePage"
        android:layout_width="23dp"
        android:layout_height="23dp"
        android:src="@drawable/sel_btn_home_page"
        app:layout_constraintBottom_toTopOf="@+id/tvHomePage"
        app:layout_constraintEnd_toStartOf="@id/ivCommunity"
        app:layout_constraintHorizontal_chainStyle="spread_inside"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.eyepetizer.android.ui.common.view.TypefaceTextView
        android:id="@+id/tvHomePage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:enabled="false"
        android:gravity="center"
        android:text="@string/homepage"
        android:textColor="@color/sel_bottom_navigation_bar_radio_color"
        android:textSize="8sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="@id/ivHomePage"
        app:layout_constraintStart_toStartOf="@id/ivHomePage"
        app:layout_constraintTop_toBottomOf="@id/ivHomePage"
        app:typeface="fzlLTypeface" />

    <ImageView
        android:id="@+id/ivCommunity"
        android:layout_width="23dp"
        android:layout_height="23dp"
        android:padding="2dp"
        android:src="@drawable/sel_btn_community"
        app:layout_constraintBottom_toTopOf="@id/tvCommunity"
        app:layout_constraintEnd_toStartOf="@id/ivRelease"
        app:layout_constraintStart_toEndOf="@id/ivHomePage"
        app:layout_constraintTop_toTopOf="parent" />

    <com.eyepetizer.android.ui.common.view.TypefaceTextView
        android:id="@+id/tvCommunity"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:enabled="false"
        android:gravity="center"
        android:text="@string/community"
        android:textColor="@color/sel_bottom_navigation_bar_radio_color"
        android:textSize="8sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="@id/ivCommunity"
        app:layout_constraintStart_toStartOf="@id/ivCommunity"
        app:layout_constraintTop_toBottomOf="@+id/ivCommunity"
        app:typeface="fzlLTypeface" />

    <ImageView
        android:id="@+id/ivRelease"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@drawable/btn_release_normal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/ivNotification"
        app:layout_constraintStart_toEndOf="@id/ivCommunity"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/ivNotification"
        android:layout_width="23dp"
        android:layout_height="23dp"
        android:padding="1dp"
        android:src="@drawable/sel_btn_notification"
        app:layout_constraintBottom_toTopOf="@id/tvNotification"
        app:layout_constraintEnd_toStartOf="@id/ivMine"
        app:layout_constraintStart_toEndOf="@id/ivRelease"
        app:layout_constraintTop_toTopOf="parent" />

    <com.eyepetizer.android.ui.common.view.TypefaceTextView
        android:id="@+id/tvNotification"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:enabled="false"
        android:gravity="center"
        android:text="@string/notification"
        android:textColor="@color/sel_bottom_navigation_bar_radio_color"
        android:textSize="8sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="@id/ivNotification"
        app:layout_constraintStart_toStartOf="@id/ivNotification"
        app:layout_constraintTop_toBottomOf="@+id/ivNotification"
        app:typeface="fzlLTypeface" />

    <ImageView
        android:id="@+id/ivMine"
        android:layout_width="23dp"
        android:layout_height="23dp"
        android:padding="2dp"
        android:src="@drawable/sel_btn_mine"
        app:layout_constraintBottom_toTopOf="@id/tvMine"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/ivNotification"
        app:layout_constraintTop_toTopOf="parent" />

    <com.eyepetizer.android.ui.common.view.TypefaceTextView
        android:id="@+id/tvMine"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:enabled="false"
        android:gravity="center"
        android:text="@string/mine"
        android:textColor="@color/sel_bottom_navigation_bar_radio_color"
        android:textSize="8sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="@id/ivMine"
        app:layout_constraintStart_toStartOf="@id/ivMine"
        app:layout_constraintTop_toBottomOf="@+id/ivMine"
        app:typeface="fzlLTypeface" />


    <androidx.constraintlayout.widget.Group
        android:id="@+id/btnHomePage"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="@+id/tvHomePage"
        app:layout_constraintEnd_toEndOf="@id/ivHomePage"
        app:layout_constraintStart_toStartOf="@id/ivHomePage"
        app:layout_constraintTop_toTopOf="@+id/ivHomePage"
        tools:background="@color/blackAlpha50" />

    <androidx.constraintlayout.widget.Group
        android:id="@+id/btnCommunity"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="@+id/tvCommunity"
        app:layout_constraintEnd_toEndOf="@id/ivCommunity"
        app:layout_constraintStart_toStartOf="@id/ivCommunity"
        app:layout_constraintTop_toTopOf="@+id/ivCommunity"
        tools:background="@color/blackAlpha50" />

    <androidx.constraintlayout.widget.Group
        android:id="@+id/btnNotification"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="@+id/tvNotification"
        app:layout_constraintEnd_toEndOf="@id/ivNotification"
        app:layout_constraintStart_toStartOf="@id/ivNotification"
        app:layout_constraintTop_toTopOf="@+id/ivNotification"
        tools:background="@color/blackAlpha50" />

    <androidx.constraintlayout.widget.Group
        android:id="@+id/btnMine"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="@+id/tvMine"
        app:layout_constraintEnd_toEndOf="@id/ivMine"
        app:layout_constraintStart_toStartOf="@id/ivMine"
        app:layout_constraintTop_toTopOf="@+id/ivMine"
        tools:background="@color/blackAlpha50" />

</androidx.constraintlayout.widget.ConstraintLayout>

11 FlycoTabLayout_Lib 的使用
12 GSYVideoPlayer 播放器的使用
https://codechina.csdn.net/mirrors/CarGuo/GSYVideoPlayer
主要自定义 三个视频类型
一个列表
一个是详情里面
一个是单独界面的详情

13.多个点击事件的处理

fun setOnClickListener(vararg v: View?, block: View.() -> Unit) {
val listener = View.OnClickListener { it.block() }
v.forEach { it?.setOnClickListener(listener) }
}

setOnClickListener(
ivMore, ivAvatar, tvLoginTips, tvFavorites, tvCache, tvFollow, tvWatchRecord, tvNotificationToggle,
tvMyBadge, tvFeedback, tvContribute, tvVersionNumber, rootView, llScrollViewContent
) {
when (this) {
ivMore -> SettingActivity.start(activity)

            ivAvatar, tvLoginTips, tvFavorites, tvCache, tvFollow, tvWatchRecord, tvNotificationToggle, tvMyBadge -> {
                LoginActivity.start(activity)
            }
            tvContribute -> {
                WebViewActivity.start(activity, WebViewActivity.DEFAULT_TITLE, Const.Url.AUTHOR_OPEN, false, false)
            }
            tvFeedback -> {
                WebViewActivity.start(activity, WebViewActivity.DEFAULT_TITLE, WebViewActivity.DEFAULT_URL, true, false, MODE_SONIC_WITH_OFFLINE_CACHE)
            }
            tvVersionNumber -> {
                WebViewActivity.start(activity, WebViewActivity.DEFAULT_TITLE, WebViewActivity.DEFAULT_URL, true, false, MODE_SONIC_WITH_OFFLINE_CACHE)
            }
            this@MineFragment.rootView, llScrollViewContent -> {
                MobclickAgent.onEvent(activity, Const.Mobclick.EVENT4)
                AboutActivity.start(activity)
            }

            else -> {
            }
        }
    }

14 携程+kolint +Retrofit网络请求

基础

object ServiceCreator {

    const val BASE_URL = "http://baobab.kaiyanapp.com/"

    val httpClient = OkHttpClient.Builder()
        .addInterceptor(LoggingInterceptor())
        .addInterceptor(HeaderInterceptor())
        .addInterceptor(BasicParamsInterceptor())
        .build()

    private val builder = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .client(httpClient)
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create(GsonBuilder().registerTypeAdapterFactory(GsonTypeAdapterFactory()).create()))

    private val retrofit = builder.build()

    fun <T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)
}
interface MainPageService {

    /**
     * 首页-发现列表
     */
    @GET
    fun getDiscovery(@Url url: String): Call<Discovery>
}

然后在封装

 suspend fun refreshVideoRelatedAndVideoReplies(videoId: Long, repliesUrl: String) = requestVideoRelatedAndVideoReplies(videoId, repliesUrl)

    suspend fun refreshVideoDetail(videoId: Long, repliesUrl: String) = requestVideoDetail(videoId, repliesUrl)

    private suspend fun requestVideoReplies(url: String) = withContext(Dispatchers.IO) {
        coroutineScope {
            val deferredVideoReplies = async { network.fetchVideoReplies(url) }
            val videoReplies = deferredVideoReplies.await()
            videoReplies
        }
    }

    private suspend fun requestVideoRelatedAndVideoReplies(videoId: Long, repliesUrl: String) = withContext(Dispatchers.IO) {
        coroutineScope {
            val deferredVideoRelated = async { network.fetchVideoRelated(videoId) }
            val deferredVideoReplies = async { network.fetchVideoReplies(repliesUrl) }
            val videoRelated = deferredVideoRelated.await()
            val videoReplies = deferredVideoReplies.await()
            val videoDetail = VideoDetail(null, videoRelated, videoReplies)
            videoDetail
        }
    }

返回neiwork的里面的内容

  private suspend fun requestHotSearch() = withContext(Dispatchers.IO) {
        val response = eyepetizerNetwork.fetchHotSearch()
        mainPageDao.cacheHotSearch(response)
        response
    }

    companion object {

        private var repository: MainPageRepository? = null

        fun getInstance(dao: MainPageDao, network: EyepetizerNetwork): MainPageRepository {
            if (repository == null) {
                synchronized(MainPageRepository::class.java) {
                    if (repository == null) {
                        repository = MainPageRepository(dao, network)
                    }
                }
            }

            return repository!!
        }
    }

解决使用携程就行了




原文地址:访问原文地址
快照地址: 访问文章快照