褶曲😀


最近の投稿では、Jetpack WindowManagerをアプリに統合する方法を紹介しました.この起業家はこの基礎を築く.我々は、姿勢の変更後のユーザーインターフェイスを調整するに焦点を当てる.この記事のコードスニペットは私のサンプルアプリケーションfoldabledemoに属しています.それはGitHubで利用可能です.

折り畳み式とタブレット
Googleが2011年初めにアンドロイドハニカムをリリースしたとき、ほとんどの既存のアプリは、モトローラXoomとすぐ後に続く他のタブレットによく見えませんでした.どうやって?開発者は確かに大画面サイズには使用されませんでした.我々はすべての新しいAPIと概念を把握するために必要.いくつかの(断片のような)が一般的になった一方、他の人は広く受け入れられた受け入れを得なかったようです.今日でも.なぜ他の多くのアプリは、タブレットが提供する大画面の不動産から恩恵を受けないだろうか?主な課題は以下の通りです.
  • は、ユーザーがポートレートモード(それがどのようにスマートフォンが保持されているので)
  • に強制的に
  • すべてのタブレットで動作しない(実際、私は対応するエラーメッセージを表示しようとするかなりの数のアプリを知っている)
  • は、スマートフォンユーザインタフェース
  • の拡大されたバージョンを示す
    foldablesを使用すると、我々のアプリを設計するときに考慮する別のデバイスのカテゴリがあります.幸運にも、テーブルのために何が真実であるかについてかなり多くのものは折り畳み式のためにも真実です.と逆も同様です.だから、何かの理由で、あなたのアプリは、タブレット上で良い見ていない場合は、速度を取得する:それを準備してください-そして折り紙のために.
    そして、それが本当に単純であるので、拒絶の弁解がありません.
    見てみましょう.
    タブレットが風景モード(垂直方向よりも画面上に多くの部屋がある)に保持されると、ユーザーインターフェイスを2つの列に分割できます.一般的なパターンは、左側にリストを表示し、その右側にコンテンツエリアです.これはマスター詳細インターフェイスと呼ばれます.両方のコラムのための33と66パーセントは広く受け入れられた比率であるようです.
    表示される内容に応じて、3つの列を利用したい場合があります.これは通常33 : 33 : 33の分布につながります.つのコラムが完璧にタブレット(1つのスクリーンから成る)で働く間、彼らは2つのスクリーンがヒンジによって接続されている装置でうまく機能しません:

    このようなデバイスでは、2つのカラムアプローチが適しています.

    慎重にいくつかのUI要素がヒンジによって影響を受ける可能性があります参照してください上記のスクリーンショットを見てください.これらは、より微妙な不具合です.私は将来の記事で彼らに話しかけます.

    ユーザーインターフェイスの作成
    あなたのユーザーインターフェイスをスマートフォン、タブレット、および折り畳み式で最適に動作するように、あなたのアプリは、これらの質問に答えて、それに応じて行動する必要があります:
  • アム私は大きな画面で実行していますか?
  • は、UIの部分を妨げるヒンジがありますか?
  • ヒンジの構成は?
  • だから、どのように我々は、構成アプリケーションの画面サイズを決定することができますか?Jetpack WindowManagerを使用するので、1つのアプローチはcurrentWindowMetricsに問い合わせます.ここでは、foldabledemoの主な活動を示します.
    class MainActivity : ComponentActivity() {
      override fun onCreate(savedInstanceState: Bundle?) {
        val r = windowInfoRepository()
        super.onCreate(savedInstanceState)
        setContent {
          val m by r.currentWindowMetrics.collectAsState(null)
          val i by r.windowLayoutInfo.collectAsState(null)
          Scaffold(modifier = Modifier.fillMaxSize(),
            topBar = {
              TopAppBar(title = {
                Text(stringResource(id = R.string.app_name))
              })
            }) {
            Content(
              m,
              i
            )
          }
        }
      }
    }
    
    WindowInfoRepository(これはwindowInfoRepository()の拡張機能である)を呼び出すことによってActivityのインスタンスを取得し、その後、州としてWindowMetricsWindowMetricsのインスタンスを取得します.私がnullに両方を初期化するので、Content()はこれの世話をしなければなりません:
    @Composable
    fun Content(
      windowMetrics: WindowMetrics?,
      windowLayoutInfo: WindowLayoutInfo?
    ) {
      Surface(modifier = Modifier.fillMaxSize()) {
        windowMetrics?.let { wm ->
          val widthDp = with(LocalDensity.current) {
            wm.bounds.width().toDp()
          }
          if (widthDp < 600.dp) {
            Box(
              modifier = Modifier
                .fillMaxSize()
                .background(Color.Yellow)
            )
          } else {
    
    WindowMetricsboundsプロパティを持っています.我々が生のピクセルを扱っているように、我々はandroid.graphics.Rectを密度独立ピクセルに変えなければなりません.その後、我々は簡単にスマートフォンやタブレット/折り畳みユーザーインターフェイスをしたいかどうかを確認することができます.スマートフォンモードでは、私の例は1つだけ黄色のボックスを示しています.

    次に、私の2番目の質問には、UIの部分を妨げるヒンジがあります.つの列を使用するとき、その内容の重要な部分が見えないかもしれないので、我々は知っている必要があります.width()をチェックすることでこれを確認できます.医者は言う

    Calculates if a FoldingFeature should be thought of as splitting the window into multiple physical areas that can be seen by users as logically separate. Display panels connected by a hinge are always separated. Folds on flexible screens should be treated as separating when they are not FoldingFeature.State.FLAT.


    とにかく折り目の範囲を得る必要があるので、私のコードはisSeparatingを使わず、代わりにisSeparatingに依存します.

    Calculates the occlusion mode to determine if a FoldingFeature occludes a part of the window. This flag is useful for determining if UI elements need to be moved around so that the user can access them. For some devices occluded elements can not be accessed by the user at all.


    次のコードスニペットは、ギャップの幅、および左右の領域の幅を決定します.いくつかの状況では、その方向が垂直であるときだけ、ヒンジに反応することは意味をなすかもしれません.これも私のコードで示されています.
    var hasGap = false
    var sizeLeft = 0
    var sizeRight = 0
    var widthGap = 0
    windowLayoutInfo?.displayFeatures?.forEach { displayFeature ->
      (displayFeature as FoldingFeature).run {
        hasGap = occlusionType == FoldingFeature.OcclusionType.FULL
            && orientation == FoldingFeature.Orientation.VERTICAL
        sizeLeft = bounds.left
        sizeRight = wm.bounds.width() - bounds.right
        widthGap = bounds.width()
      }
    }
    
    では、得られた値で何ができるかを見ましょう.
    Row(
      modifier = Modifier.fillMaxSize(),
    ) {
      if (hasGap) {
        val width = (wm.bounds.width() - widthGap).toFloat()
        val weightLeft = sizeLeft.toFloat() / width
        val weightRight = sizeRight.toFloat() / width
        ColouredBoxWithWeight(weightLeft, Color.Red)
        Spacer(
          modifier = Modifier
            .requiredWidth(with(LocalDensity.current) {
              widthGap.toDp()
            })
            .fillMaxHeight()
        )
        ColouredBoxWithWeight(weightRight, Color.Green)
      } else {
        ColouredBoxWithWeight(0.333F, Color.Red)
        ColouredBoxWithWeight(0.333F, Color.Green)
        ColouredBoxWithWeight(0.333F, Color.Blue)
      }
    }
    
    ギャップがない場合は、アプリケーションは3つの列モードです.これは、3つの均等に着色されたボックスを示しています.
    しかし、我々はギャップを検出した場合、アプリケーションは2つの列を示しています.ギャップは、必要な幅を有するocclusionTypeによって表される.左右の領域は重みを付けて大きさを定める.たぶんあなたはなぜ私は正確にそれらを計算するために設計疑問に思っている.それはちょうどSpacer()を使用して簡単になりませんか?私のアルゴリズムは、2つの表示半分が幅で等しくない場合に機能します.私はこれらの特性を持つデバイスがあるかどうかわからないが、その後、私のアプリは、安全な側にあります.😎


    結論
    あなたは色の箱の周りに薄い白い境界を発見したことがありますか?私は、サイズが正しく計算されることを確認するために、彼らをそこに置きました.あなたが見たように、両方のタブレットとfoldablesの認識可能なUIを認識することは本当に簡単です.だから、何を停止している?がんばれ.そして、コメントであなたの考えを共有してください.