我創建了一個帶有底部導航欄和幾個片段的簡單應用,其中一個片段 ( ArFragment) 顯示相機預覽:

MainActivity.kt:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val bottomBar = findViewById<BottomNavigationView>(R.id.bottom_navigation)
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
bottomBar.setupWithNavController(navHostFragment.navController)
}
}
activity_main.xml:
<LinearLayout
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:id="@ id/main_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activities.MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@ id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@ id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/windowBackground"
app:menu="@menu/bottom_navigation_menu" />
</LinearLayout>
ArFragment.kt:
class ArFragment : Fragment() {
private lateinit var cameraExecutor: ExecutorService
private lateinit var binding: FragmentArBinding
private val cameraPermissionResultReceiver =
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
if (it) {
startCamera()
} else {
binding.viewFinder.visibility = View.GONE
binding.errorTextView.visibility = View.VISIBLE
binding.frameLayout.invalidate()
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentArBinding.inflate(inflater, container, false)
// Request camera permissions
when {
allPermissionsGranted() -> startCamera()
shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> {
showRationaleDialog()
}
else -> cameraPermissionResultReceiver.launch(Manifest.permission.CAMERA)
}
cameraExecutor = Executors.newSingleThreadExecutor()
return binding.root
}
private fun showRationaleDialog() {
AlertDialog.Builder(requireContext())
.setTitle(R.string.rationale_title_camera)
.setMessage(R.string.rationale_body_camera)
.setPositiveButton(R.string.action_ok) { _, _ ->
cameraPermissionResultReceiver.launch(Manifest.permission.CAMERA)
}
.create()
.show()
}
override fun onDestroy() {
super.onDestroy()
cameraExecutor.shutdown()
}
private fun startCamera() {
context?.let { ctx ->
val cameraProviderFuture = ProcessCameraProvider.getInstance(ctx)
cameraProviderFuture.addListener({
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview
val preview = Preview.Builder()
.build()
.also {
it.setSurfaceProvider(binding.viewFinder.surfaceProvider)
}
// Select back camera as a default
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
// Unbind use cases before rebinding
cameraProvider.unbindAll()
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, cameraSelector, preview
)
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(ctx))
}
}
private fun allPermissionsGranted() = ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
companion object {
private const val TAG = "ArFragment"
}
}
fragment_ar.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@ id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.ArFragment">
<androidx.camera.view.PreviewView
android:id="@ id/viewFinder"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@ id/errorTextView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:layout_margin="24dp"
android:visibility="gone"
android:text="@string/error_no_camera_permissions" />
</FrameLayout>
The camera preview works perfectly but I can't make it to fit all screen space, please, don't confuse with a fullscreen mode. I want to make status, tab and navigation bars transparent for ArFragment (and only for ArFragment). In short, to the camera preview became like a root layer background. A something similar to our iOS version:

P.S. I've tried solutions from similar questions. To use android:fitsSystemWindows="true" and so on. It works, it makes them transparent but I need to the camera preview could fill all available screen space. At this moment I think that the camera output must be rendered as a root layout background but I am not sure if it's a right way. And even if it's a right way, I don't know how to implement it.
uj5u.com熱心網友回復:
我正在做類似的事情。不完全相同,但希望這與作業說明足夠接近,可以讓您到達那里。
您需要使片段視圖填充整個父級,因此它位于導航欄的后面。但是,當您在不是相機視圖的片段上時,您還需要將其更改為位于導航欄上方,否則您的某些內容將被導航欄和底部系統欄覆寫。
我會使用 ConstraintLayout 來實作這一點。
您需要從 to 切換,fragment以便androidx.fragment.app.FragmentContainerView能夠修改布局引數以在兩種狀態之間切換。
另外,使底部導航視圖的高度為 0dp,因為如果它是透明的,它的高度陰影會看起來非常奇怪。
底部導航視圖將提供也將在底部系統欄后面的顏色
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@ id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@ id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:elevation="0dp"
app:navGraph="@navigation/nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@ id/nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:elevation="0dp"
app:menu="@menu/bottom_navigation_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
您的主題應具有以下屬性。這使得系統導航欄不可見(或者在 Android Q 之前的設備上至少是半透明的)。在 Android L 之前的設備上,我認為它沒有做任何事情,而且你只是運氣不好讓它變得透明。
<item name="android:navigationBarColor" tools:targetApi="l">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds" tools:targetApi="l">true</item>
<item name="android:enforceNavigationBarContrast" tools:targetApi="q">false</item>
在您的活動中onCreate添加此行,這對于半透明/透明底部導航欄也是必需的。
WindowCompat.setDecorFitsSystemWindows(window, false)
你需要findNavController(nav_host_fragment)用這個替換,因為我們從一個fragment元素切換到一個FragmentContainerView:
(supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController
最后,在 Activity 中創建一個函式,您將在切換到相機片段時呼叫該函式。(您可以使用它navController.addOnDestinationChangedListener來呼叫它。)
private fun setFragmentBehindNavigation(behind: Boolean) {
// swap where the bottom edge of fragment is aligned
binding.navHostFragmentActivityMain.apply {
layoutParams = (layoutParams as ConstraintLayout.LayoutParams).apply {
if (behind) {
bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID
bottomToTop = ConstraintLayout.LayoutParams.UNSET
} else {
bottomToBottom = ConstraintLayout.LayoutParams.UNSET
bottomToTop = R.id.nav_view
}
}
}
// swap between opaque and translucent bottom nav color
binding.navView.setBackgroundColor(
resources.getColor(
if (fits) R.color.someTranslucentColor else R.color.someOpaqueColor
)
)
}
We still haven't handled the problem of your views going behind the top status bar when you aren't showing the camera preview. If you're using a Toolbar on all your other fragments, I think it will be fine because Toolbars know how to use fitsSystemWindows (not all types of view can handle it correctly). If you're not, one solution is to insert a plain old View between the top of the parent constraint layout and the top of the fragment container using constraints. Then at runtime, you set this view to the height of the top status bar. Set it between GONE and VISIBLE in the setFragmentBehindNavigation function above.
困難的部分是使它與系統欄的高度相同。我已經沒有時間來回答這個問題了(我認為這會很快,但已經過了一個多小時了!)所以我不能為此添加更多說明,但你可以閱讀這篇文章,了解如何去做吧。非常復雜!
uj5u.com熱心網友回復:
我顯然不明白你想隱藏什么。狀態欄或導航但是,如果你想隱藏你的狀態欄,那么使用這個代碼。
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
這適用于 Build.VERSION.SDK_INT 大于 16;
// Hide the status bar.
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
或者,如果您還想隱藏底部導航欄,那么它也很簡單。您可以使用 Runnable 將其隱藏在您選擇的時間范圍內。
uj5u.com熱心網友回復:
用于getActionbar.hide()避免在螢屏上顯示操作欄,如果您的操作欄被隱藏,相機將展開以占據整個螢屏
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/454180.html
下一篇:在Kotlin中讀取YAML檔案
