最近看的一个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>
- 友盟统计的使用
下载
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{}
- 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!!
}
}
解决使用携程就行了
网友评论