优化:MainActivity 内容填充方式(避免一次性加载多个Fragment)&& 提升APP启动速度与稳定性
优化:左滑菜单 与 TabBar 美化 精简:界面调整 & 去除不常用资源 整理:code reviewpull/408/head
@ -0,0 +1,83 @@
|
||||
package com.idormy.sms.forwarder.adapter.menu
|
||||
|
||||
import android.util.SparseArray
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
@Suppress("LeakingThis", "UNCHECKED_CAST")
|
||||
class DrawerAdapter(private val items: List<DrawerItem<out ViewHolder>>) : RecyclerView.Adapter<DrawerAdapter.ViewHolder>() {
|
||||
|
||||
private val viewTypes: MutableMap<Class<out DrawerItem<*>>, Int> = HashMap()
|
||||
private val holderFactories = SparseArray<DrawerItem<*>>()
|
||||
|
||||
private var listener: OnItemSelectedListener? = null
|
||||
|
||||
init {
|
||||
processViewTypes()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val holder = holderFactories.get(viewType).createViewHolder(parent)
|
||||
holder.adapter = this
|
||||
return holder
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
(items[position] as DrawerItem<ViewHolder>).bindViewHolder(holder)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = items.size
|
||||
|
||||
override fun getItemViewType(position: Int): Int = viewTypes[items[position]::class.java] ?: -1
|
||||
|
||||
private fun processViewTypes() {
|
||||
var type = 0
|
||||
items.forEach { item ->
|
||||
if (!viewTypes.containsKey(item::class.java)) {
|
||||
viewTypes[item::class.java] = type
|
||||
holderFactories.put(type, item)
|
||||
type++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setSelected(position: Int) {
|
||||
val newChecked = items[position]
|
||||
if (!newChecked.isSelectable()) return
|
||||
|
||||
items.forEachIndexed { index, item ->
|
||||
if (item.isChecked()) {
|
||||
item.setChecked(false)
|
||||
notifyItemChanged(index)
|
||||
return@forEachIndexed
|
||||
}
|
||||
}
|
||||
|
||||
newChecked.setChecked(true)
|
||||
notifyItemChanged(position)
|
||||
|
||||
listener?.onItemSelected(position)
|
||||
}
|
||||
|
||||
fun setListener(listener: OnItemSelectedListener?) {
|
||||
this.listener = listener
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
abstract class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
|
||||
var adapter: DrawerAdapter? = null
|
||||
|
||||
init {
|
||||
itemView.setOnClickListener(this)
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
adapter?.setSelected(adapterPosition)
|
||||
}
|
||||
}
|
||||
|
||||
interface OnItemSelectedListener {
|
||||
fun onItemSelected(position: Int)
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.idormy.sms.forwarder.adapter.menu
|
||||
|
||||
import android.view.ViewGroup
|
||||
|
||||
abstract class DrawerItem<T : DrawerAdapter.ViewHolder> {
|
||||
private var isChecked = false
|
||||
|
||||
abstract fun createViewHolder(parent: ViewGroup): T
|
||||
abstract fun bindViewHolder(holder: T)
|
||||
|
||||
fun setChecked(checked: Boolean): DrawerItem<T> {
|
||||
isChecked = checked
|
||||
return this
|
||||
}
|
||||
|
||||
fun isChecked(): Boolean = isChecked
|
||||
|
||||
open fun isSelectable(): Boolean = true
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.idormy.sms.forwarder.adapter.menu
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.idormy.sms.forwarder.R
|
||||
|
||||
class SimpleItem(
|
||||
private val icon: Drawable,
|
||||
private val title: String,
|
||||
private var selectedItemIconTint: Int = 0,
|
||||
private var selectedItemTextTint: Int = 0,
|
||||
private var normalItemIconTint: Int = 0,
|
||||
private var normalItemTextTint: Int = 0
|
||||
) : DrawerItem<SimpleItem.ViewHolder>() {
|
||||
|
||||
override fun createViewHolder(parent: ViewGroup): ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val v = inflater.inflate(R.layout.menu_item_option, parent, false)
|
||||
return ViewHolder(v)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(holder: ViewHolder) {
|
||||
holder.title.text = title
|
||||
holder.icon.setImageDrawable(icon)
|
||||
|
||||
holder.title.setTextColor(if (isChecked()) selectedItemTextTint else normalItemTextTint)
|
||||
holder.icon.setColorFilter(if (isChecked()) selectedItemIconTint else normalItemIconTint)
|
||||
}
|
||||
|
||||
fun withSelectedIconTint(selectedItemIconTint: Int): SimpleItem = apply {
|
||||
this.selectedItemIconTint = selectedItemIconTint
|
||||
}
|
||||
|
||||
fun withSelectedTextTint(selectedItemTextTint: Int): SimpleItem = apply {
|
||||
this.selectedItemTextTint = selectedItemTextTint
|
||||
}
|
||||
|
||||
fun withIconTint(normalItemIconTint: Int): SimpleItem = apply {
|
||||
this.normalItemIconTint = normalItemIconTint
|
||||
}
|
||||
|
||||
fun withTextTint(normalItemTextTint: Int): SimpleItem = apply {
|
||||
this.normalItemTextTint = normalItemTextTint
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View) : DrawerAdapter.ViewHolder(itemView) {
|
||||
val icon: ImageView = itemView.findViewById(R.id.icon)
|
||||
val title: TextView = itemView.findViewById(R.id.title)
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.idormy.sms.forwarder.adapter.menu
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
||||
class SpaceItem(private val spaceDp: Int) : DrawerItem<SpaceItem.ViewHolder>() {
|
||||
|
||||
override fun createViewHolder(parent: ViewGroup): ViewHolder {
|
||||
val context: Context = parent.context
|
||||
val view = View(context).apply {
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, (context.resources.displayMetrics.density * spaceDp).toInt()
|
||||
)
|
||||
}
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(holder: ViewHolder) {}
|
||||
|
||||
override fun isSelectable(): Boolean = false
|
||||
|
||||
class ViewHolder(itemView: View) : DrawerAdapter.ViewHolder(itemView)
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="?attr/colorAccent" android:state_pressed="true" />
|
||||
<item android:color="?attr/colorAccent" android:state_selected="true" />
|
||||
<item android:color="@color/xui_btn_disable_color" android:state_enabled="false" />
|
||||
<item android:color="?attr/colorAccent" />
|
||||
</selector>
|
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com)
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:color="?attr/colorAccent" />
|
||||
<item android:state_selected="true" android:color="?attr/colorAccent" />
|
||||
<item android:color="@color/xui_config_color_gray_6" />
|
||||
</selector>
|
Before Width: | Height: | Size: 242 B |
Before Width: | Height: | Size: 194 B |
Before Width: | Height: | Size: 300 B |
Before Width: | Height: | Size: 543 B |
Before Width: | Height: | Size: 397 B |
Before Width: | Height: | Size: 434 B |
@ -0,0 +1,5 @@
|
||||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:tint="#FFFFFF" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M11.67,3.87L9.9,2.1 0,12l9.9,9.9 1.77,-1.77L3.54,12z"/>
|
||||
</vector>
|
@ -0,0 +1,24 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M895.11,191.93 L381.96,191.93c-35.15,0 -63.64,28.49 -63.64,63.64 0,35.15 28.49,63.64 63.64,63.64l513.15,0c35.15,0 63.64,-28.49 63.64,-63.64C958.75,220.43 930.26,191.93 895.11,191.93z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M895.11,449.81 L381.96,449.81c-35.15,0 -63.64,28.49 -63.64,63.64 0,35.15 28.49,63.64 63.64,63.64l513.15,0c35.15,0 63.64,-28.49 63.64,-63.64C958.75,478.3 930.26,449.81 895.11,449.81z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M893.06,703.59 L379.91,703.59c-35.15,0 -63.64,28.49 -63.64,63.64 0,35.15 28.49,63.64 63.64,63.64l513.15,0c35.15,0 63.64,-28.49 63.64,-63.64C956.7,732.08 928.21,703.59 893.06,703.59z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M130.65,257.03m-61.4,0a60,60 0,1 0,122.8 0,60 60,0 1,0 -122.8,0Z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M124.51,514.9m-61.4,0a60,60 0,1 0,122.8 0,60 60,0 1,0 -122.8,0Z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M126.55,766.63m-61.4,0a60,60 0,1 0,122.8 0,60 60,0 1,0 -122.8,0Z" />
|
||||
</vector>
|
Before Width: | Height: | Size: 414 B After Width: | Height: | Size: 414 B |
@ -1,12 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM7.68,14.98H6V9h1.71c1.28,0 1.71,1.03 1.71,1.71l0,2.56C9.42,13.95 9,14.98 7.68,14.98zM12.38,11.46v1.07h-1.18v1.39h1.93v1.07h-2.25c-0.4,0.01 -0.74,-0.31 -0.75,-0.71V9.75c-0.01,-0.4 0.31,-0.74 0.71,-0.75h2.28l0,1.07h-1.92v1.39H12.38zM16.88,14.23c-0.48,1.11 -1.33,0.89 -1.71,0L13.77,9h1.18l1.07,4.11L17.09,9h1.18L16.88,14.23z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:pathData="M7.77,10.12H7.14v3.77h0.63c0.14,0 0.28,-0.05 0.42,-0.16c0.14,-0.1 0.21,-0.26 0.21,-0.47v-2.52c0,-0.21 -0.07,-0.37 -0.21,-0.47C8.05,10.17 7.91,10.12 7.77,10.12z" />
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:pathData="M19,5v14L5,19L5,5h14m1.1,-2L3.9,3c-0.5,0 -0.9,0.4 -0.9,0.9v16.2c0,0.4 0.4,0.9 0.9,0.9h16.2c0.4,0 0.9,-0.5 0.9,-0.9L21,3.9c0,-0.5 -0.5,-0.9 -0.9,-0.9zM11,7h6v2h-6L11,7zM11,11h6v2h-6v-2zM11,15h6v2h-6zM7,7h2v2L7,9zM7,11h2v2L7,13zM7,15h2v2L7,17z" />
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:pathData="M16.54,11L13,7.46l1.41,-1.41l2.12,2.12l4.24,-4.24l1.41,1.41L16.54,11zM11,7H2v2h9V7zM21,13.41L19.59,12L17,14.59L14.41,12L13,13.41L15.59,16L13,18.59L14.41,20L17,17.41L19.59,20L21,18.59L18.41,16L21,13.41zM11,15H2v2h9V15z" />
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z" />
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z" />
|
||||
</vector>
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |