parent
0b00a5dd00
commit
d2c0cfd478
@ -0,0 +1,204 @@ |
|||||||
|
package io.legado.app.ui.book.read |
||||||
|
|
||||||
|
import android.annotation.SuppressLint |
||||||
|
import android.content.Context |
||||||
|
import android.content.res.ColorStateList |
||||||
|
import android.graphics.drawable.GradientDrawable |
||||||
|
import android.util.AttributeSet |
||||||
|
import android.view.Gravity |
||||||
|
import android.view.LayoutInflater |
||||||
|
import android.view.View.OnClickListener |
||||||
|
import android.view.View.OnLongClickListener |
||||||
|
import android.view.WindowManager |
||||||
|
import android.view.animation.Animation |
||||||
|
import android.widget.FrameLayout |
||||||
|
import android.widget.SeekBar |
||||||
|
import androidx.activity.viewModels |
||||||
|
import androidx.appcompat.widget.SearchView |
||||||
|
import androidx.core.view.isVisible |
||||||
|
import io.legado.app.R |
||||||
|
import io.legado.app.constant.PreferKey |
||||||
|
import io.legado.app.databinding.ViewSearchMenuBinding |
||||||
|
import io.legado.app.help.* |
||||||
|
import io.legado.app.lib.dialogs.alert |
||||||
|
import io.legado.app.lib.theme.* |
||||||
|
import io.legado.app.model.ReadBook |
||||||
|
import io.legado.app.ui.book.info.BookInfoActivity |
||||||
|
import io.legado.app.ui.book.searchContent.SearchContentViewModel |
||||||
|
import io.legado.app.ui.browser.WebViewActivity |
||||||
|
import io.legado.app.ui.widget.seekbar.SeekBarChangeListener |
||||||
|
import io.legado.app.utils.* |
||||||
|
import splitties.views.* |
||||||
|
|
||||||
|
/** |
||||||
|
* 阅读界面菜单 |
||||||
|
*/ |
||||||
|
class SearchMenu @JvmOverloads constructor( |
||||||
|
context: Context, attrs: AttributeSet? = null |
||||||
|
) : FrameLayout(context, attrs) { |
||||||
|
private val searchView: SearchView by lazy { |
||||||
|
binding.titleBar.findViewById(R.id.search_view) |
||||||
|
} |
||||||
|
|
||||||
|
val viewModel by viewModels<SearchContentViewModel>() |
||||||
|
|
||||||
|
private val callBack: CallBack get() = activity as CallBack |
||||||
|
private val binding = ViewSearchMenuBinding.inflate(LayoutInflater.from(context), this, true) |
||||||
|
private val menuTopIn: Animation = AnimationUtilsSupport.loadAnimation(context, R.anim.anim_readbook_top_in) |
||||||
|
private val menuTopOut: Animation = AnimationUtilsSupport.loadAnimation(context, R.anim.anim_readbook_top_out) |
||||||
|
private val menuBottomIn: Animation = AnimationUtilsSupport.loadAnimation(context, R.anim.anim_readbook_bottom_in) |
||||||
|
private val menuBottomOut: Animation = AnimationUtilsSupport.loadAnimation(context, R.anim.anim_readbook_bottom_out) |
||||||
|
private val bgColor: Int = context.bottomBackground |
||||||
|
private val textColor: Int = context.getPrimaryTextColor(ColorUtils.isColorLight(bgColor)) |
||||||
|
private val bottomBackgroundList: ColorStateList = |
||||||
|
Selector.colorBuild().setDefaultColor(bgColor).setPressedColor(ColorUtils.darkenColor(bgColor)).create() |
||||||
|
private var onMenuOutEnd: (() -> Unit)? = null |
||||||
|
private var hasSearchResult: Boolean = true |
||||||
|
|
||||||
|
init { |
||||||
|
initAnimation() |
||||||
|
initView() |
||||||
|
bindEvent() |
||||||
|
} |
||||||
|
|
||||||
|
private fun initView() = binding.run { |
||||||
|
llSearchBaseInfo.setBackgroundColor(bgColor) |
||||||
|
tvCurrentSearchInfo.setTextColor(bottomBackgroundList) |
||||||
|
llBottomBg.setBackgroundColor(bgColor) |
||||||
|
fabLeft.backgroundTintList = bottomBackgroundList |
||||||
|
fabLeft.setColorFilter(textColor) |
||||||
|
fabRight.backgroundTintList = bottomBackgroundList |
||||||
|
fabRight.setColorFilter(textColor) |
||||||
|
tvMainMenu.setTextColor(textColor) |
||||||
|
tvSearchResults.setTextColor(textColor) |
||||||
|
tvSearchExit.setTextColor(textColor) |
||||||
|
tvSetting.setTextColor(textColor) |
||||||
|
ivMainMenu.setColorFilter(textColor) |
||||||
|
ivSearchResults.setColorFilter(textColor) |
||||||
|
ivSearchExit.setColorFilter(textColor) |
||||||
|
ivSetting.setColorFilter(textColor) |
||||||
|
ivSearchContentBottom.setColorFilter(textColor) |
||||||
|
ivSearchContentTop.setColorFilter(textColor) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
fun runMenuIn() { |
||||||
|
this.visible() |
||||||
|
binding.titleBar.visible() |
||||||
|
binding.llSearchBaseInfo.visible() |
||||||
|
binding.llBottomBg.visible() |
||||||
|
binding.titleBar.startAnimation(menuTopIn) |
||||||
|
binding.llSearchBaseInfo.startAnimation(menuBottomIn) |
||||||
|
binding.llBottomBg.startAnimation(menuBottomIn) |
||||||
|
} |
||||||
|
|
||||||
|
fun runMenuOut(onMenuOutEnd: (() -> Unit)? = null) { |
||||||
|
this.onMenuOutEnd = onMenuOutEnd |
||||||
|
if (this.isVisible) { |
||||||
|
binding.titleBar.startAnimation(menuTopOut) |
||||||
|
binding.llSearchBaseInfo.startAnimation(menuBottomOut) |
||||||
|
binding.llBottomBg.startAnimation(menuBottomOut) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun bindEvent() = binding.run { |
||||||
|
titleBar.toolbar.setOnClickListener { |
||||||
|
ReadBook.book?.let { |
||||||
|
context.startActivity<BookInfoActivity> { |
||||||
|
putExtra("name", it.name) |
||||||
|
putExtra("author", it.author) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
llSearchResults.setOnClickListener { |
||||||
|
runMenuOut { |
||||||
|
callBack.returnSearchActivity() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//主菜单 |
||||||
|
llMainMenu.setOnClickListener { |
||||||
|
runMenuOut { |
||||||
|
callBack.showMenuBar() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
//目录 |
||||||
|
llSearchExit.setOnClickListener { |
||||||
|
runMenuOut { |
||||||
|
callBack.searchExit() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//设置 |
||||||
|
llSetting.setOnClickListener { |
||||||
|
runMenuOut { |
||||||
|
callBack.showSearchSetting() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun initAnimation() { |
||||||
|
//显示菜单 |
||||||
|
menuTopIn.setAnimationListener(object : Animation.AnimationListener { |
||||||
|
override fun onAnimationStart(animation: Animation) { |
||||||
|
callBack.upSystemUiVisibility() |
||||||
|
binding.fabLeft.visible(hasSearchResult) |
||||||
|
binding.fabRight.visible(hasSearchResult) |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressLint("RtlHardcoded") |
||||||
|
override fun onAnimationEnd(animation: Animation) { |
||||||
|
val navigationBarHeight = if (ReadBookConfig.hideNavigationBar) { |
||||||
|
activity?.navigationBarHeight ?: 0 |
||||||
|
} else { |
||||||
|
0 |
||||||
|
} |
||||||
|
binding.run { |
||||||
|
vwMenuBg.setOnClickListener { runMenuOut() } |
||||||
|
root.padding = 0 |
||||||
|
when (activity?.navigationBarGravity) { |
||||||
|
Gravity.BOTTOM -> root.bottomPadding = navigationBarHeight |
||||||
|
Gravity.LEFT -> root.leftPadding = navigationBarHeight |
||||||
|
Gravity.RIGHT -> root.rightPadding = navigationBarHeight |
||||||
|
} |
||||||
|
} |
||||||
|
callBack.upSystemUiVisibility() |
||||||
|
} |
||||||
|
|
||||||
|
override fun onAnimationRepeat(animation: Animation) = Unit |
||||||
|
}) |
||||||
|
|
||||||
|
//隐藏菜单 |
||||||
|
menuTopOut.setAnimationListener(object : Animation.AnimationListener { |
||||||
|
override fun onAnimationStart(animation: Animation) { |
||||||
|
binding.vwMenuBg.setOnClickListener(null) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onAnimationEnd(animation: Animation) { |
||||||
|
this@SearchMenu.invisible() |
||||||
|
binding.titleBar.invisible() |
||||||
|
binding.llSearchBaseInfo.invisible() |
||||||
|
binding.llBottomBg.invisible() |
||||||
|
binding.fabRight.invisible() |
||||||
|
binding.fabLeft.invisible() |
||||||
|
onMenuOutEnd?.invoke() |
||||||
|
callBack.upSystemUiVisibility() |
||||||
|
} |
||||||
|
|
||||||
|
override fun onAnimationRepeat(animation: Animation) = Unit |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
interface CallBack { |
||||||
|
var isShowingSearchResult: Boolean |
||||||
|
fun returnSearchActivity() |
||||||
|
fun showSearchSetting() |
||||||
|
fun upSystemUiVisibility() |
||||||
|
fun searchExit() |
||||||
|
fun showMenuBar() |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,276 @@ |
|||||||
|
<?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="match_parent" |
||||||
|
android:orientation="vertical"> |
||||||
|
|
||||||
|
<View |
||||||
|
android:id="@+id/vw_menu_bg" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:contentDescription="@string/content" |
||||||
|
tools:layout_editor_absoluteX="0dp" |
||||||
|
tools:layout_editor_absoluteY="0dp" /> |
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton |
||||||
|
android:id="@+id/fabLeft" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_margin="16dp" |
||||||
|
android:contentDescription="上个结果" |
||||||
|
android:src="@drawable/ic_search" |
||||||
|
android:tint="@color/primaryText" |
||||||
|
android:tooltipText="@string/search_content" |
||||||
|
app:backgroundTint="@color/background_menu" |
||||||
|
app:elevation="2dp" |
||||||
|
app:fabSize="mini" |
||||||
|
app:pressedTranslationZ="2dp" |
||||||
|
tools:ignore="UnusedAttribute" |
||||||
|
app:layout_constraintStart_toStartOf="parent" |
||||||
|
app:layout_constraintTop_toTopOf="parent" |
||||||
|
app:layout_constraintBottom_toBottomOf="parent"/> |
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton |
||||||
|
android:id="@+id/fabRight" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_margin="16dp" |
||||||
|
android:contentDescription="下个结果" |
||||||
|
android:src="@drawable/ic_search" |
||||||
|
android:tint="@color/primaryText" |
||||||
|
android:tooltipText="@string/search_content" |
||||||
|
app:backgroundTint="@color/background_menu" |
||||||
|
app:elevation="2dp" |
||||||
|
app:fabSize="mini" |
||||||
|
app:pressedTranslationZ="2dp" |
||||||
|
tools:ignore="UnusedAttribute" |
||||||
|
app:layout_constraintEnd_toEndOf="parent" |
||||||
|
app:layout_constraintTop_toTopOf="parent" |
||||||
|
app:layout_constraintBottom_toBottomOf="parent"/> |
||||||
|
|
||||||
|
<io.legado.app.ui.widget.TitleBar |
||||||
|
android:id="@+id/title_bar" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
app:contentLayout="@layout/view_search" |
||||||
|
app:contentInsetRight="24dp" |
||||||
|
app:layout_constraintTop_toTopOf="parent" /> |
||||||
|
|
||||||
|
<io.legado.app.ui.widget.anima.RefreshProgressBar |
||||||
|
android:id="@+id/refresh_progress_bar" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="2dp" |
||||||
|
app:layout_constraintTop_toBottomOf="@id/title_bar"/> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:id="@+id/ll_search_base_info" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="36dp" |
||||||
|
android:background="@color/background_menu" |
||||||
|
android:gravity="center_vertical" |
||||||
|
android:orientation="horizontal" |
||||||
|
android:paddingLeft="10dp" |
||||||
|
android:paddingRight="10dp" |
||||||
|
app:layout_constraintBottom_toTopOf="@id/ll_bottom_bg"> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_current_search_info" |
||||||
|
android:layout_width="0dp" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_weight="1" |
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless" |
||||||
|
android:ellipsize="middle" |
||||||
|
android:gravity="center_vertical" |
||||||
|
android:paddingLeft="10dp" |
||||||
|
android:paddingRight="10dp" |
||||||
|
android:singleLine="true" |
||||||
|
android:textColor="@color/primaryText" |
||||||
|
android:textSize="12sp" /> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/iv_search_content_top" |
||||||
|
android:layout_width="36dp" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless" |
||||||
|
android:contentDescription="@string/go_to_top" |
||||||
|
android:src="@drawable/ic_arrow_drop_up" |
||||||
|
android:tooltipText="@string/go_to_top" |
||||||
|
app:tint="@color/primaryText" |
||||||
|
tools:ignore="UnusedAttribute" /> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/iv_search_content_bottom" |
||||||
|
android:layout_width="36dp" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless" |
||||||
|
android:contentDescription="@string/go_to_bottom" |
||||||
|
android:src="@drawable/ic_arrow_drop_down" |
||||||
|
android:tooltipText="@string/go_to_bottom" |
||||||
|
app:tint="@color/primaryText" |
||||||
|
tools:ignore="UnusedAttribute" /> |
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:id="@+id/ll_bottom_bg" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="50dp" |
||||||
|
android:layout_marginTop="8dp" |
||||||
|
android:baselineAligned="false" |
||||||
|
android:orientation="horizontal" |
||||||
|
app:layout_constraintBottom_toBottomOf="parent"> |
||||||
|
|
||||||
|
<!--结果按钮--> |
||||||
|
<LinearLayout |
||||||
|
android:id="@+id/ll_search_results" |
||||||
|
android:layout_width="50dp" |
||||||
|
android:layout_height="50dp" |
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless" |
||||||
|
android:clickable="true" |
||||||
|
android:contentDescription="结果" |
||||||
|
android:focusable="true" |
||||||
|
android:orientation="vertical" |
||||||
|
android:paddingBottom="7dp"> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/iv_search_results" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="0dp" |
||||||
|
android:layout_weight="1" |
||||||
|
android:contentDescription="结果" |
||||||
|
android:src="@drawable/ic_toc" |
||||||
|
app:tint="@color/primaryText" |
||||||
|
tools:ignore="NestedWeights" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_search_results" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_gravity="center_horizontal" |
||||||
|
android:layout_marginTop="3dp" |
||||||
|
android:text="结果" |
||||||
|
android:maxLines="1" |
||||||
|
android:textColor="@color/primaryText" |
||||||
|
android:textSize="12sp" /> |
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<View |
||||||
|
android:layout_width="0dp" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_weight="2" /> |
||||||
|
<!--调节按钮--> |
||||||
|
<LinearLayout |
||||||
|
android:id="@+id/ll_main_menu" |
||||||
|
android:layout_width="50dp" |
||||||
|
android:layout_height="50dp" |
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless" |
||||||
|
android:clickable="true" |
||||||
|
android:contentDescription="@string/read_aloud" |
||||||
|
android:focusable="true" |
||||||
|
android:orientation="vertical" |
||||||
|
android:paddingBottom="7dp"> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/iv_main_menu" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="0dp" |
||||||
|
android:layout_weight="1" |
||||||
|
android:contentDescription="@string/main_menu" |
||||||
|
android:src="@drawable/ic_menu" |
||||||
|
app:tint="@color/primaryText" |
||||||
|
tools:ignore="NestedWeights" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_main_menu" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_gravity="center_horizontal" |
||||||
|
android:layout_marginTop="3dp" |
||||||
|
android:text="@string/main_menu" |
||||||
|
android:maxLines="1" |
||||||
|
android:textColor="@color/primaryText" |
||||||
|
android:textSize="12sp" /> |
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
<View |
||||||
|
android:layout_width="0dp" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_weight="2" /> |
||||||
|
<!--界面按钮--> |
||||||
|
<LinearLayout |
||||||
|
android:id="@+id/ll_search_exit" |
||||||
|
android:layout_width="50dp" |
||||||
|
android:layout_height="50dp" |
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless" |
||||||
|
android:clickable="true" |
||||||
|
android:contentDescription="退出" |
||||||
|
android:focusable="true" |
||||||
|
android:orientation="vertical" |
||||||
|
android:paddingBottom="7dp"> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/iv_search_exit" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="0dp" |
||||||
|
android:layout_weight="1" |
||||||
|
android:contentDescription="退出" |
||||||
|
android:src="@drawable/ic_auto_page_stop" |
||||||
|
app:tint="@color/primaryText" |
||||||
|
tools:ignore="NestedWeights" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_search_exit" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_gravity="center_horizontal" |
||||||
|
android:layout_marginTop="3dp" |
||||||
|
android:text="退出" |
||||||
|
android:maxLines="1" |
||||||
|
android:textColor="@color/primaryText" |
||||||
|
android:textSize="12sp" /> |
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
<View |
||||||
|
android:layout_width="0dp" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_weight="2" /> |
||||||
|
<!--设置按钮--> |
||||||
|
<LinearLayout |
||||||
|
android:id="@+id/ll_setting" |
||||||
|
android:layout_width="50dp" |
||||||
|
android:layout_height="50dp" |
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless" |
||||||
|
android:clickable="true" |
||||||
|
android:contentDescription="@string/setting" |
||||||
|
android:focusable="true" |
||||||
|
android:orientation="vertical" |
||||||
|
android:paddingBottom="7dp"> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/iv_setting" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="0dp" |
||||||
|
android:layout_weight="1" |
||||||
|
android:contentDescription="@string/aloud_config" |
||||||
|
android:src="@drawable/ic_settings" |
||||||
|
app:tint="@color/primaryText" |
||||||
|
tools:ignore="NestedWeights" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_setting" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_gravity="center_horizontal" |
||||||
|
android:layout_marginTop="3dp" |
||||||
|
android:text="@string/setting" |
||||||
|
android:maxLines="1" |
||||||
|
android:textColor="@color/primaryText" |
||||||
|
android:textSize="12sp" /> |
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout> |
Loading…
Reference in new issue