commit
20a516196a
@ -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