Android pad分屏遇到的一些问题

博客讨论了在pad横屏状态下,应用程序出现视频显示异常,仅占据窗口三分之一,导致宽度小于高度的情况。尽管设备处于横屏,但app内部却执行了针对竖屏的代码逻辑,这可能涉及到屏幕方向检测和适配的错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 如图

分屏后 视频只占大约三分之一的窗口 导致视频的宽度要比高度小

这种情况下,虽然pad是横屏状态,但是对于app来说 会执行竖屏的代码逻辑

/********************************************************************* * * Copyright (C), 2010-2022 Oplus. All rights reserved.. * * VENDOR_EDIT * * File : AddFilePanelFragment.kt * * Description : AddFilePanelFragment * * Version : 1.0 * * Date : 2025/02/08 * * Author : W9085798 * * * * ---------------------Revision History: ---------------------------- * * <author> <data> <version> <desc> ***********************************************************************/ package com.oplus.filemanager.addfilepanel.ui import android.annotation.SuppressLint import android.app.Activity import android.os.SystemClock import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.RelativeLayout import android.widget.TextView import androidx.annotation.VisibleForTesting import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider import com.coui.appcompat.button.COUIButton import com.coui.appcompat.button.SingleButtonWrap import com.coui.appcompat.contextutil.COUIContextUtil import com.coui.appcompat.panel.COUIBottomSheetDialog import com.coui.appcompat.panel.COUIBottomSheetDialogFragment import com.coui.appcompat.panel.COUIPanelFragment import com.coui.appcompat.panel.COUIPanelMultiWindowUtils import com.coui.appcompat.tablayout.COUITab import com.coui.appcompat.tablayout.COUITabLayout import com.coui.appcompat.toolbar.COUIToolbar import com.filemanager.common.MyApplication.appContext import com.filemanager.common.base.BaseFileBean import com.filemanager.common.base.BaseFragmentAdapter import com.filemanager.common.constants.Constants import com.filemanager.common.controller.LoadingController import com.filemanager.common.controller.PrivacyPolicyController import com.filemanager.common.helper.MimeTypeHelper import com.filemanager.common.helper.uiconfig.UIConfigMonitor import com.filemanager.common.utils.Injector import com.filemanager.common.utils.KtViewUtils import com.filemanager.common.utils.Log import com.filemanager.common.utils.ModelUtils import com.filemanager.common.utils.SdkUtils import com.filemanager.common.utils.StatusBarUtil import com.filemanager.common.utils.Utils import com.filemanager.common.utils.dp2px import com.filemanager.common.view.ViewPagerWrapperForPC import com.filemanager.common.view.viewpager.RTLViewPager import com.oplus.filemanager.addfilepanel.R import com.oplus.filemanager.addfilepanel.bean.AddFileBean import com.oplus.filemanager.addfilepanel.viewmodel.AddFilePanelViewModel import com.oplus.filemanager.interfaze.categorydoc.IDocumentExtensionType import com.oplus.filemanager.interfaze.main.IMain import kotlin.properties.Delegates class AddFilePanelFragment : COUIPanelFragment(), COUITabLayout.OnTabSelectedListener, PrivacyPolicyController.OnPrivacyPolicyListener { companion object { private const val TAG = "ShortcutFolderAddFilePanelFragment" private const val NUM = 1024 private const val DECIMAL_NUM = 1024f private const val DISMISS_TIME_GAP = 1000L private const val DELAY_TIME = 50L private const val PANEL_MAX_HEIGHT = "panel_max_height" } var lifeCycle: Lifecycle by Delegates.notNull() var title: String? = null var mCurrentPath: String = "" private var disMissTime: Long = 0L private var toolBar: COUIToolbar? = null private var mTabTitle = arrayListOf( appContext.resources.getString(com.filemanager.common.R.string.total), appContext.resources.getString(com.filemanager.common.R.string.string_photos), appContext.resources.getString(com.filemanager.common.R.string.string_videos), appContext.resources.getString(com.filemanager.common.R.string.string_audio), appContext.resources.getString(com.filemanager.common.R.string.string_documents), appContext.resources.getString(com.filemanager.common.R.string.string_other) ) private val mTabTitles = intArrayOf( Constants.TAB_ALL, Constants.TAB_IMAGE, Constants.TAB_VIDEO, Constants.TAB_AUDIO, Constants.TAB_DOCUMENT, Constants.TAB_OTHER ) private var mAddFileDialogInterface: AddFileDialogInterface? = null private var mPages: ArrayList<AddFileListFragment> = ArrayList() private var mViewPager: RTLViewPager? = null private var mTabView: COUITabLayout? = null private var mViewPagerWrapper: ViewPagerWrapperForPC? = null private var addFileBtn: COUIButton? = null private var verticalButtonWrap: SingleButtonWrap? = null private var rootView: ViewGroup? = null private var addFilePanelViewModel: AddFilePanelViewModel? = null private var statisticsSelectTitleView: TextView? = null private var statisticsSelectBodyView: TextView? = null private var contentLayout: RelativeLayout? = null private var buttonDivider: View? = null private var statisticsArrowUpView: ImageView? = null private var statisticsRootView: ViewGroup? = null private var loadingController: LoadingController? = null private var mPosition: Int = 0 var limitCount: Int = 0 private val allFiles: MutableList<BaseFileBean> = mutableListOf() private val imageFiles: MutableList<BaseFileBean> = mutableListOf() private val videoFiles: MutableList<BaseFileBean> = mutableListOf() private val audioFiles: MutableList<BaseFileBean> = mutableListOf() private val docFiles: MutableList<BaseFileBean> = mutableListOf() private val otherFiles: MutableList<BaseFileBean> = mutableListOf() private val mSelectArrayByID: MutableSet<Long> = mutableSetOf() var addFileClickCallback: (selectData: List<AddFileBean>) -> Unit = {} var isExternalReference: Boolean = false private fun setPanelMaxHeight() { if (activity == null) return rootView?.layoutParams?.apply { if (UIConfigMonitor.isCurrentZoomWindowShow() && SdkUtils.isAtLeastR() && !isExternalReference) { val savedHeight: Int = arguments?.getInt(PANEL_MAX_HEIGHT) ?: 0 Log.d(TAG, "setPanelMaxHeight savedHeight = $savedHeight") if (savedHeight == 0) { // 处理浮窗 height = handleZoomWindowHeight(requireActivity(), height) arguments?.putInt(PANEL_MAX_HEIGHT, height) } else { height = savedHeight } Log.d(TAG, "setPanelMaxHeight height = $height") } else { val screenHeight = dp2px(requireActivity(), requireActivity().resources.configuration.screenHeightDp) val panelMaxHeight = COUIPanelMultiWindowUtils.getPanelMaxHeight(requireActivity(), requireActivity().resources.configuration) Log.d(TAG, "setPanelMaxHeight screenHeight:$screenHeight panelH:$panelMaxHeight height:$height") //当是分屏 if (requireActivity().isInMultiWindowMode) { if (StatusBarUtil.checkIsGestureNavMode(requireActivity())) { //全面屏手势导航 height = handleGestureNavModeHeight(requireActivity(), height) } else { // 底部导航栏 height = Math.min(screenHeight, panelMaxHeight) - requireActivity().resources.getDimensionPixelOffset( com.filemanager.common.R.dimen.dimen_40dp ) height = handleNavModeHeight(requireActivity(), height) } } rootView?.layoutParams = this } } } /** * 处理浮窗模式下的高度 */ private fun handleZoomWindowHeight(activity: Activity, height: Int): Int { var result = height val statusBarH = COUIPanelMultiWindowUtils.getStatusBarHeight(activity) val configuration = activity.resources.configuration val paddingBottom = COUIPanelMultiWindowUtils.getPanelMarginBottom(context, configuration) val rect = COUIPanelMultiWindowUtils.getCurrentWindowVisibleRect(activity) if (rect != null) { if (rect.top == 0) { Log.d(TAG, "handleZoomWindowHeight: rect $rect top is invalid, reset") rect.top = activity.resources.getDimensionPixelOffset(com.filemanager.common.R.dimen.panel_min_top_margin) } if (rect.bottom == 0) { val windowH = KtViewUtils.getWindowSize(activity).y rect.bottom = windowH Log.d(TAG, "handleZoomWindowHeight: rect $rect bottom is invalid, reset $windowH") } result = (rect.bottom - rect.top) - paddingBottom - statusBarH Log.d(TAG, "handleZoomWindowHeight: height $result = ${rect.bottom}-${rect.top}-$paddingBottom-$statusBarH") } return result } /** * 处理底部导航栏导航时的高度 */ private fun handleNavModeHeight(it: Activity, height: Int): Int { val navBarHeight = KtViewUtils.getSoftNavigationBarSize(it) var result = height when { ModelUtils.isTablet() -> { //平板竖屏分屏时 if (UIConfigMonitor.instance.isDevicePortrait(it)) { result = height - navBarHeight Log.d(TAG, "handleNavMode pad portrait height:$result") } } UIConfigMonitor.instance.isFoldable(it) -> { // 折叠屏 result = height - navBarHeight Log.d(TAG, "handleNavMode fold height:$result") } else -> { //手机且分屏处于下屏 if (!COUIPanelMultiWindowUtils.isDisplayInUpperWindow(it)) { result = height - navBarHeight Log.d(TAG, "handleNavMode phone lower split screen height:$result") } } } return result } /** * 处理全面屏手势导航时的高度 */ @VisibleForTesting fun handleGestureNavModeHeight(activity: Activity, height: Int): Int { if (COUIPanelMultiWindowUtils.isDisplayInUpperWindow(activity)) { // 上分屏,不用处理 return height } // 处于下分屏,并且显示了手势指示条 if (StatusBarUtil.checkShowGestureNavBar(activity)) { val result = height - activity.resources.getDimensionPixelOffset(com.filemanager.common.R.dimen.dimen_16dp) Log.d(TAG, "handleGestureNavMode lower split screen with show gesture nvaBar height:$result") return result } return height } override fun onDestroy() { Log.d(TAG, "onDestroy") super.onDestroy() verticalButtonWrap?.release() clearDataList() addFilePanelViewModel?.onDestroy() } override fun initView(panelView: View?) { activity?.let { activity -> LayoutInflater.from(activity).inflate(getLayoutResId(), null, false)?.let { (contentView as? ViewGroup)?.addView(it) initContentView(it) initViewModel(activity) startObserver() initData() } } } private fun getLayoutResId(): Int { return R.layout.add_file_panel_dialog } private fun initViewModel(act: FragmentActivity) { addFilePanelViewModel = ViewModelProvider(act)[AddFilePanelViewModel::class.java] } private fun startObserver() { addFilePanelViewModel?.mAllFiles?.observe(this) { it ?: return@observe showLoadingView(false) setViewPagerData(it) } addFilePanelViewModel?.mAllSelectFiles?.observe(this) { it ?: return@observe updateStatisticsSelectView(it) } } fun notifyUpdate() { mSelectArrayByID.clear() addFilePanelViewModel?.mAllSelectFiles?.value?.forEach { bean -> if (bean.isSelected) { bean.mFileID?.let { mSelectArrayByID.add(it) } } } getCurrentFragment()?.apply { setSelectedData(mSelectArrayByID) notifyUpdate() } } private fun initContentView(view: View) { Log.d(TAG, "initContentView") hideDragView() rootView = view.findViewById(R.id.dialog_layout) toolBar = view.findViewById(R.id.toolbar) mTabView = view.findViewById<COUITabLayout?>(R.id.tab_layout) mViewPager = view.findViewById(R.id.viewPager) mViewPagerWrapper = view.findViewById<ViewPagerWrapperForPC?>(R.id.view_pager_wrapper).apply { notifyMainViewPager = object : ((Boolean) -> Unit) { override fun invoke(enable: Boolean) { activity?.let { val mainAction = Injector.injectFactory<IMain>() mainAction?.setViewPagerScrollEnabled(it, enable) } } } } addFileBtn = view.findViewById<COUIButton?>(R.id.btn_add_file).apply { verticalButtonWrap = SingleButtonWrap(this, SingleButtonWrap.Type.Small) setOnClickListener { Log.d(TAG, "addFileBtn click. select:${addFilePanelViewModel?.mAllSelectFiles?.value?.size}") val selectList = addFilePanelViewModel?.mAllSelectFiles?.value selectList?.let { addFileClickCallback.invoke(it) } } } contentLayout = view.findViewById(R.id.content_layout) buttonDivider = view.findViewById(R.id.button_divider) statisticsSelectTitleView = view.findViewById<TextView?>(R.id.select_title_content) statisticsSelectBodyView = view.findViewById<TextView?>(R.id.select_body_content) statisticsArrowUpView = view.findViewById(R.id.select_arraw_up) statisticsRootView = view.findViewById<ViewGroup?>(R.id.select_root_view).apply { setOnClickListener { if (Utils.isQuickClick()) { Log.w(TAG, "click too fast, try later") return@setOnClickListener } addFilePanelViewModel?.mAllSelectFiles?.value?.let { mAddFileDialogInterface?.replaceSelectedPanelFragment(it) } } } setPanelMaxHeight() } private fun initData() { initToolBar() resetStatisticsView() val fragments = childFragmentManager.fragments for (i in mTabTitles.indices) { initFragment(i, fragments) } initViewPager() if (PrivacyPolicyController.hasAgreePrivacy()) { loadData() } else { PrivacyPolicyController.bindPrivacyPolicyListener(this) } } private fun loadData() { Log.d(TAG, "loadData") showLoadingView(true) // 加载数据 activity?.let { addFilePanelViewModel?.loadAllFiles(it) } } private fun resetStatisticsView() { addFileBtn?.isEnabled = false statisticsSelectTitleView?.apply { visibility = View.VISIBLE text = appContext.resources.getString(com.filemanager.common.R.string.not_selected_file) } statisticsSelectBodyView?.apply { visibility = View.GONE text = "" } statisticsArrowUpView?.apply { visibility = View.GONE } statisticsRootView?.apply { isClickable = false } } private fun initToolBar() { toolBar?.apply { visibility = View.VISIBLE title = appContext.resources.getString(com.filemanager.common.R.string.encryption_file_select_title) isTitleCenterStyle = true inflateMenu(R.menu.add_file_panel_dialog_menu_bar) menu.findItem(R.id.cancel).setOnMenuItemClickListener { mAddFileDialogInterface?.dismissAddFileDialog() true } } if ((mTabView != null) && (mViewPager != null)) { mTabView?.let { it.setupWithViewPager(mViewPager, false) it.addOnTabSelectedListener(this) it.isUpdateindicatorposition = true } } } fun setAddFileDialogInterface(addFileDialog: AddFileDialogInterface) { mAddFileDialogInterface = addFileDialog } private fun initViewPager() { mViewPager?.let { it.offscreenPageLimit = mTabTitles.size it.adapter = ViewPagerFragmentStateAdapter(this) it.currentItem = 0 it.overScrollMode = View.OVER_SCROLL_NEVER } } private fun initFragment(position: Int, fragments: List<Fragment>): Fragment { Log.d(TAG, "initFragment") var fragment = if (fragments.isEmpty()) null else fragments[position] if (fragment == null) { fragment = AddFileListFragment() fragment.isExternalReference = isExternalReference fragment.lifeCycle = lifeCycle fragment.mOnItemSelectCallback = { _, fileID -> mSelectArrayByID.add(fileID) addFilePanelViewModel?.updateAllSelectFiles(mSelectArrayByID) } fragment.mOnItemUnSelectCallback = { _, fileID -> mSelectArrayByID.remove(fileID) addFilePanelViewModel?.updateAllSelectFiles(mSelectArrayByID) } fragment.mFileEmptyCallback = { isShowEmpty -> handleFileEmptyView(isShowEmpty) } fragment.mCurrentPath = mCurrentPath fragment.limitCount = limitCount } if (fragment is AddFileListFragment) { mPages.add(fragment) } return fragment } private fun handleFileEmptyView(isShowEmptyView: Boolean) { if (isShowEmptyView) { showLoadingView(false) buttonDivider?.alpha = 0F } else { buttonDivider?.alpha = 1F } } private fun showLoadingView(isShow: Boolean) { if (isShow) { Log.d(TAG, "showLoadingView disMissTime $disMissTime") activity?.let { loadingController = LoadingController(it, this) //如果异常loadingView刚刚调用,就不调用显示loadingView,防止loadingView一直显示 Log.d(TAG, "showLoadingView getLoadingShowStartTime ${loadingController?.getLoadingShowStartTime()}") if (SystemClock.elapsedRealtime() - disMissTime >= DISMISS_TIME_GAP || loadingController?.getLoadingShowStartTime() == 0L) { loadingController?.showLoading(contentLayout) } } } else { Log.d(TAG, "showLoadingView dismissLoading") loadingController?.dismissLoading() disMissTime = SystemClock.elapsedRealtime() } } override fun onShow(isShowOnFirstPanel: Boolean?) { super.onShow(isShowOnFirstPanel) ((parentFragment as? COUIBottomSheetDialogFragment)?.dialog as? COUIBottomSheetDialog) ?.setPanelBackgroundTintColor(COUIContextUtil.getAttrColor(context, com.support.appcompat.R.attr.couiColorBackgroundElevatedWithCard)) } private fun clearDataList() { allFiles.clear() imageFiles.clear() videoFiles.clear() audioFiles.clear() docFiles.clear() otherFiles.clear() mSelectArrayByID.clear() } private fun setViewPagerData(data: MutableList<AddFileBean>) { Log.d(TAG, "setViewPagerData") clearDataList() allFiles.addAll(data) val documentExtensionType = Injector.injectFactory<IDocumentExtensionType>() data.forEach { file -> val localType = file.mLocalType if (MimeTypeHelper.isImageType(localType)) { imageFiles.add(file) } else if (MimeTypeHelper.isVideoType(localType)) { videoFiles.add(file) } else if (MimeTypeHelper.isAudioType(localType)) { audioFiles.add(file) } else if ((MimeTypeHelper.isDocType(localType) || MimeTypeHelper.isOtherDocType(localType)) && documentExtensionType?.isCategoryDocSupportType(file) == true ) { //isCategoryDocSupportType确保面板上文档分类显示的内容和文管文档分类一致(部分未知格式后缀会识解析TXT类型) docFiles.add(file) } else { otherFiles.add(file) } } updateData(mTabTitles[mPosition]) } private fun updateStatisticsSelectView(data: MutableList<AddFileBean>) { if (data.size <= 0) { Log.d(TAG, "unselect file") resetStatisticsView() return } addFileBtn?.isEnabled = true statisticsSelectTitleView?.apply { visibility = View.VISIBLE text = appContext.resources.getQuantityString( com.filemanager.common.R.plurals.mark_selected_items_new, data.size, data.size ) } statisticsSelectBodyView?.apply { visibility = View.VISIBLE val size: Long = data.sumOf { it.mSize } val totalSize: String = updateSizeFormat(size) text = appContext.resources.getString(com.filemanager.common.R.string.selected_size, totalSize) } statisticsArrowUpView?.apply { visibility = View.VISIBLE } statisticsRootView?.apply { isClickable = true } } @SuppressLint("DefaultLocale") fun updateSizeFormat(size: Long): String { return if (size < NUM) { size.toString() + "B" } else if (size < NUM * NUM) { String.format("%.1f", (size / DECIMAL_NUM)) + " KB" } else if (size < NUM * NUM * NUM) { String.format("%.1f", (size / NUM / DECIMAL_NUM)) + " MB" } else { String.format("%.1f", (size / NUM / NUM / DECIMAL_NUM)) + " GB" } } private fun updateData(fragmentType: Int) { val fragment = getCurrentFragment() fragment?.mFragmentType = fragmentType when (fragmentType) { Constants.TAB_ALL -> fragment?.setData(allFiles) Constants.TAB_IMAGE -> fragment?.setData(imageFiles) Constants.TAB_VIDEO -> fragment?.setData(videoFiles) Constants.TAB_AUDIO -> fragment?.setData(audioFiles) Constants.TAB_DOCUMENT -> fragment?.setData(docFiles) Constants.TAB_OTHER -> fragment?.setData(otherFiles) } fragment?.setSelectedData(mSelectArrayByID) Log.d( TAG, "allFiles=${allFiles.size}, imageFiles=${imageFiles.size}, videoFiles=${videoFiles.size}, " + "audioFiles=${audioFiles.size}, docFiles=${docFiles.size}, otherFiles=${otherFiles.size}" ) } override fun onTabSelected(tab: COUITab?) { Log.d(TAG, "onTabSelected tab.postion=${tab?.position}") tab?.let { mPosition = it.position if (loadingController?.isShowing() != true) { updateData(mTabTitles[mPosition]) } } } override fun onTabUnselected(p0: COUITab?) {} override fun onTabReselected(p0: COUITab?) {} private fun getCurrentFragment(): AddFileListFragment? { return if (mPosition < mPages.size) { mPages[mPosition] } else { null } } inner class ViewPagerFragmentStateAdapter(fragment: Fragment) : BaseFragmentAdapter(fragment) { override fun getItemCount(): Int { return mTabTitle.size } override fun createFragment(position: Int): Fragment { return mPages[position] } override fun getPageTitle(position: Int): CharSequence { return mTabTitle[position] } } override fun onAgreeResult(agree: Boolean, noLongerRemind: Boolean) { loadData() } } interface AddFileDialogInterface { fun dismissAddFileDialog() fun replaceSelectedPanelFragment(selectData: MutableList<AddFileBean>) }这是对应的kotlin代码,怎么处理
最新发布
07-29
<think>我们之前的目标是:在不改变原有布局的情况下,解决大字体和维吾尔语环境下文本挤压问题。 根据提供的代码,我们需要修改的是`updateStatisticsSelectView`方法,因为该方法负责更新统计选择视图(即显示选中文件数量和总大小的TextView)。 修改思路: 1. 在更新文本之前,先计算文本控件的最大可用宽度(根据屏幕宽度、按钮宽度和边距计算)。 2. 设置文本控件的最大宽度,并启用省略功能(ellipsize)和单行显示(singleLine)。 3. 添加对RTL(从右向左)语言的支持,如维吾尔语。 4. 添加长按显示完整内容的功能。 但是,由于我们无法在XML中修改,因此需要在代码中动态设置这些属性。 具体修改步骤: 在`updateStatisticsSelectView`方法中,当有选中的文件时(即data.size > 0),在设置文本之前,先进行以下操作: - 获取屏幕宽度、按钮宽度和边距(这里边距我们使用16dp,左右各16dp,所以总共32dp)。 - 计算文本控件的最大宽度:屏幕宽度 - 按钮宽度 - 边距(还要考虑一些安全边距)。 - 设置`statisticsSelectTitleView`和`statisticsSelectBodyView`的最大宽度。 - 设置省略方式和单行显示。 - 对于RTL语言,设置文本方向为本地化方向(TEXT_DIRECTION_LOCALE)。 - 为文本控件添加长按监听,长按时显示完整内容。 另外,我们还需要处理字体缩放变化,重写`onConfigurationChanged`方法,当字体缩放改变时重新计算最大宽度。 但是,注意:在`updateStatisticsSelectView`中,我们每次更新选中文件时都会调用,所以当字体缩放改变时,如果选中文件存在,会触发重新计算。但为了确保万无一失,我们可以在`onConfigurationChanged`中主动调用`updateStatisticsSelectView`(如果当前有选中的文件)。 然而,由于我们的代码结构,`addFilePanelViewModel?.mAllSelectFiles`是LiveData,我们无法直接获取当前值(除非我们保存一个副本)。因此,我们可以选择在`onConfigurationChanged`中检查当前是否有选中的文件,然后重新更新视图。 但是,为了简化,我们可以在`updateStatisticsSelectView`中已经处理了动态计算,而字体缩放改变时,系统会重建Activity(默认行为),除非我们在AndroidManifest.xml中处理了configChanges。但我们的代码中并没有处理,所以通常Activity会重建,因此我们的Fragment也会重建,所以不需要额外处理。但是,如果我们希望不重建Activity,那么就需要在Fragment中监听配置变化。 根据需求,我们可能不希望重建,所以需要处理配置变化。但我们的代码中没有处理,所以默认会重建。因此,我们暂时不考虑在`onConfigurationChanged`中处理,而是依靠每次更新选中文件时重新计算。 但是,如果字体缩放改变时,当前没有选中的文件,那么`updateStatisticsSelectView`不会被调用,所以文本控件的最大宽度不会被更新。因此,我们需要在视图初始化时(比如在`initContentView`中)设置一次,并在配置变化时更新。 然而,考虑到我们的文本控件在未选中时显示的是固定文本(“未选择文件”),这个文本通常不会很长,所以问题不大。但是为了确保一致,我们可以在`resetStatisticsView`中也设置一次最大宽度(但此时没有选中文件,我们可以按照同样的逻辑设置最大宽度)。 因此,我们重构一下:将计算最大宽度的逻辑抽取成一个方法,并在`updateStatisticsSelectView`和`resetStatisticsView`中调用。 具体修改如下: 步骤1:在`initContentView`中获取按钮的宽度(注意:此时视图可能还没有测量,所以我们需要在视图布局完成后获取,或者使用ViewTreeObserver)。 但是,在`updateStatisticsSelectView`中,我们每次更新时按钮的宽度可能已经测量好了,所以可以在那里获取。 步骤2:编写一个方法`adjustTextViewsWidth`,用于调整两个文本视图的宽度。 步骤3:在`updateStatisticsSelectView`和`resetStatisticsView`中调用`adjustTextViewsWidth`。 步骤4:添加长按监听。 步骤5:处理RTL。 由于代码较长,我们只修改`AddFilePanelFragment`类。 注意:我们还需要考虑在视图尚未测量时,按钮宽度为0的情况。我们可以使用ViewTreeObserver来监听布局完成,或者延迟到视图测量后再设置。但是,在`updateStatisticsSelectView`中,我们通常是在数据加载后调用,此时视图应该已经测量好了。 如果遇到按钮宽度为0,我们可以暂时不设置最大宽度,或者使用上次的宽度(但第一次可能没有)。我们可以延迟一段时间再设置,但这样可能不太可靠。因此,我们选择在`updateStatisticsSelectView`中,如果按钮宽度为0,则使用ViewTreeObserver监听下一次布局。 但是,为了简化,我们假设在`updateStatisticsSelectView`调用时,按钮已经测量好了。因为选中文件通常发生在用户操作之后,此时视图早已布局完成。 修改代码: 在`AddFilePanelFragment`类中添加一个方法`adjustTextViewsWidth`: 但是,由于我们无法保证按钮宽度已经存在,所以我们使用一个安全的方式来获取。 另外,我们还需要在`initContentView`中保存按钮和文本视图的引用,以便在`adjustTextViewsWidth`中使用。 由于我们已经在`initContentView`中获取了`addFileBtn`、`statisticsSelectTitleView`和`statisticsSelectBodyView`,所以可以直接使用。 修改后的代码:</think>我将基于提供的 Kotlin 代码,在不改变原有布局结构的前提下,实现大字体和维吾尔语环境下的文本挤压解决方案。以下是具体的修改方案: ### 修改点 1: 在 `updateStatisticsSelectView` 方法中添加文本适配逻辑 ```kotlin private fun updateStatisticsSelectView(data: MutableList<AddFileBean>) { if (data.size <= 0) { Log.d(TAG, "unselect file") resetStatisticsView() return } // 添加文本适配逻辑 adjustTextViewsForLargeFont() addFileBtn?.isEnabled = true statisticsSelectTitleView?.apply { visibility = View.VISIBLE text = appContext.resources.getQuantityString( com.filemanager.common.R.plurals.mark_selected_items_new, data.size, data.size ) } statisticsSelectBodyView?.apply { visibility = View.VISIBLE val size: Long = data.sumOf { it.mSize } val totalSize: String = updateSizeFormat(size) text = appContext.resources.getString(com.filemanager.common.R.string.selected_size, totalSize) } statisticsArrowUpView?.apply { visibility = View.VISIBLE } statisticsRootView?.apply { isClickable = true } } // 新增方法:适配大字体和RTL语言 @SuppressLint("ClickableViewAccessibility") private fun adjustTextViewsForLargeFont() { activity?.let { activity -> // 确保视图已布局完成 statisticsRootView?.post { // 1. 获取屏幕宽度和按钮宽度 val displayMetrics = DisplayMetrics() activity.windowManager.defaultDisplay.getMetrics(displayMetrics) val screenWidth = displayMetrics.widthPixels // 2. 计算边距(左右各16dp) val margin = resources.getDimensionPixelSize(com.filemanager.common.R.dimen.dimen_16dp) * 2 // 3. 计算最大文本宽度(屏幕宽度 - 按钮宽度 - 边距 - 安全边距) val buttonWidth = addFileBtn?.width ?: 0 val maxTextWidth = screenWidth - buttonWidth - margin - 50 // 50px安全边距 // 4. 设置文本控件最大宽度 statisticsSelectTitleView?.maxWidth = maxTextWidth statisticsSelectBodyView?.maxWidth = maxTextWidth // 5. 启用省略功能 statisticsSelectTitleView?.ellipsize = TextUtils.TruncateAt.END statisticsSelectBodyView?.ellipsize = TextUtils.TruncateAt.END // 6. 设置单行显示 statisticsSelectTitleView?.isSingleLine = true statisticsSelectBodyView?.isSingleLine = true // 7. RTL语言支持 if (TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL) { statisticsSelectTitleView?.textDirection = View.TEXT_DIRECTION_LOCALE statisticsSelectBodyView?.textDirection = View.TEXT_DIRECTION_LOCALE } // 8. 添加长按显示完整内容 statisticsSelectTitleView?.setOnLongClickListener { Toast.makeText(activity, statisticsSelectTitleView?.text, Toast.LENGTH_LONG).show() true } // 9. 超大字体适配 val fontScale = resources.configuration.fontScale if (fontScale > 1.5f) { val maxWidthRes = if (fontScale > 2.0f) { com.filemanager.common.R.dimen.xlarge_text_max_width } else { com.filemanager.common.R.dimen.large_text_max_width } val maxWidth = resources.getDimensionPixelSize(maxWidthRes) statisticsSelectTitleView?.maxWidth = maxWidth statisticsSelectBodyView?.maxWidth = maxWidth } } } } ``` ### 修改点 2: 添加字体缩放监听 ```kotlin // 在类顶部添加变量 private var currentFontScale = 1.0f // 重写 onConfigurationChanged 方法 override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) // 检测字体缩放变化 if (newConfig.fontScale != currentFontScale) { currentFontScale = newConfig.fontScale addFilePanelViewModel?.mAllSelectFiles?.value?.let { updateStatisticsSelectView(it) } } } ``` ### 修改点 3: 在 `initContentView` 中初始化变量 ```kotlin private fun initContentView(view: View) { // ... 现有代码 ... // 获取当前字体缩放比例 currentFontScale = resources.configuration.fontScale // ... 现有代码 ... } ``` ### 修改点 4: 确保按钮最小宽度 ```kotlin private fun initContentView(view: View) { // ... 现有代码 ... addFileBtn = view.findViewById<COUIButton?>(R.id.btn_add_file).apply { // 设置按钮最小宽度保护 minWidth = resources.getDimensionPixelSize(com.filemanager.common.R.dimen.button_min_width) // ... 现有代码 ... } // ... 现有代码 ... } ``` ### 修改点 5: 在 `resetStatisticsView` 中添加初始设置 ```kotlin private fun resetStatisticsView() { addFileBtn?.isEnabled = false statisticsSelectTitleView?.apply { visibility = View.VISIBLE text = appContext.resources.getString(com.filemanager.common.R.string.not_selected_file) // 初始设置 maxWidth = Int.MAX_VALUE ellipsize = null isSingleLine = false setOnLongClickListener(null) } statisticsSelectBodyView?.apply { visibility = View.GONE text = "" // 初始设置 maxWidth = Int.MAX_VALUE ellipsize = null isSingleLine = false setOnLongClickListener(null) } statisticsArrowUpView?.apply { visibility = View.GONE } statisticsRootView?.apply { isClickable = false } } ``` ### 修改点 6: 添加资源文件支持(values/dimens.xml) ```xml <!-- 添加按钮最小宽度保护 --> <dimen name="button_min_width">96dp</dimen> <!-- 超大字体下的最大文本宽度 --> <dimen name="large_text_max_width">280dp</dimen> <dimen name="xlarge_text_max_width">240dp</dimen> ``` ### 完整解决方案说明 1. **动态计算最大宽度**: - 使用 `post` 确保视图布局完成后再进行计算 - 根据屏幕宽度、按钮宽度和边距计算文本最大允许宽度 - 添加 50px 安全边距防止边缘挤压 2. **字体缩放监听**: - 在 `onConfigurationChanged` 中检测字体缩放变化 - 字体变化时重新计算文本最大宽度 3. **超大字体适配**: - 当字体缩放 > 1.5 时使用更严格的宽度限制 - 使用资源文件定义超大字体尺寸 4. **RTL语言支持**: - 检测当前语言方向(LTR/RTL) - 动态设置文本方向适配维吾尔语 5. **长按显示完整内容**: - 为被截断文本添加长按事件 - 通过 Toast 显示完整文本内容 6. **按钮保护**: - 设置按钮最小宽度,防止被过度压缩 7. **视图初始化**: - 在 `resetStatisticsView` 中重置文本属性 - 避免属性设置影响其他状态 这些修改完全在 Kotlin 代码中实现,不需要修改 XML 布局文件,保持了原有布局结构不变。主要修改集中在 `updateStatisticsSelectView` 方法和新增的 `adjustTextViewsForLargeFont` 方法中。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值