1

複合カスタム コントロールを作成しています。コントロールは、下部にある 1 つの要素と、上部にある不明な数の要素で構成されています。これらの各要素の背景は、その要素の各状態に使用する NinePatchDrawables を定義する StateListDrawable です。

個々の上部要素がコンテンツに合わせて幅を変更すると、すぐ下の下部要素の領域も幅を変更する必要があります。上部の要素の位置が左右にずれている場合もあります。

コントロール レイアウトのモックアップ

上と下の画像は、私が達成する必要があるレイアウトと動作を伝えるための簡単なモックアップです。使用する実際の背景画像をデザインする責任はありませんが、均一なフラット グレーにはなりません。

望ましいストレッチ動作

このサイズ変更の問題の最初の部分は、次の方法で解決できました。

  • Drawable を拡張するカスタム クラスを作成します。
  • クラスに、Bottom View のさまざまな潜在的な領域を定義する NinePatchDrawables の配列を渡します (例: left_end、right_end、middle_below_control、middle_below_gap)。
  • カスタム クラスの実行中に、上記の関連するビューに一致するようにそれぞれの境界を変更しますonBoundChange()
  • サイズを変更した NinePatches の配列を の Bottom View キャンバスに描画しますonDraw()
  • 配列内の NinePatches のパディングに基づいて、Bottom View の結合されたパディングを設定します。

ただし、このソリューションにはいくつかの問題があります。

  • Bottom View の潜在的な領域ごとに StateListDrawables が必要です。
  • これらの StateListDrawables のそれぞれの状態ごとに個別の NinePatch イメージが必要です。
  • 幅全体が非常に均一になるように制限されたボトムビューの画像を設計する必要があります。
  • グラフィックデザイナーからのすべての叫びに対処するには、イヤーディフェンダーと分厚い皮膚が必要です.

私が本当に達成する必要があるのは:

  • Bottom View 用に 1 つの StateListDrawable を用意します。
  • 各状態の単一の画像を抽出し、必要なセクションにスライスします。
  • 各スライスに新しい NinePatchDrawable を作成し、上記のビューのデータ チャンクを幅のみに適用します。高さではありません。
  • 次に、上記の以前のソリューションに従ってそれらを再結合します。

残念ながら、データ チャンクを実際に操作することはできません。ソース イメージからコンパイル時に生成され、NinePatch バイナリが作成されます。

この種のトピックに関するより良い回答の 1 つがここにあります。これに基づいて、可能な妥協案は次のようになります。

  • 上部の要素の種類ごとに、グラフィック デザイナーに、同じ高さと幅の寸法、同じ幅のパディングとパッチ定義を備えた追加の空のダミー NinePatch ソースを提供してもらいます。
  • getNinePatchChunk()関連するダミーの NinePatch コンパイル済みリソースで使用します。
  • 結果のデータ チャンクを関連する Bottom View ビットマップ スライスと組み合わせて、 を使用して新しい NinePatch を作成しますNinePatch(Bitmap bitmap, byte[] chunk, String srcName)
  • グラフィック デザイナーからの汚らわしい外見には我慢しますが、少なくとも彼らは怒鳴るのをやめました。

これは、物事を行うには少し不格好な方法のようです。必要なすべての目標を達成するために、これを行うためのより良い、より効率的な方法はありますか?

注:アプリで使用する場合、スクロール ビューにはこのカスタム コントロールのインスタンスが多数存在する可能性が高いため、ネストされたレイアウトは最小限に抑える必要があります。

4

1 に答える 1

0

上記の妥協案として、空のダミー NinePatch ソースを必要に応じて使用しないようにする方法を最終的に思いつきました。

同様の問題に対するこの優れた解決策に基づいて、NinePatch リソースからパディング情報を抽出するユーティリティ メソッドを作成しました。これを使用して、隣接する NinePatch 領域から必要なパディングを抽出し、それらを新しいスライスに適用できます。これが他の人に役立つことを願っています。

public static Rect getNinePatchPadding(Context context, int drawableId) {
    Rect mPadding = new Rect();
    Bitmap bm = BitmapFactory.decodeResource(context.getResources(), drawableId);
    final byte[] chunk = bm.getNinePatchChunk();
    if (!NinePatch.isNinePatchChunk(chunk)) return null;
    ByteBuffer byteBuffer = ByteBuffer.wrap(chunk).order(ByteOrder.nativeOrder());

    // Skip to padding
    for (int i = 0; i < 12; i++) {
        byteBuffer.get();
    }

    mPadding.left = byteBuffer.getInt();
    mPadding.top = byteBuffer.getInt();
    mPadding.right = byteBuffer.getInt();
    mPadding.bottom = byteBuffer.getInt();

    return mPadding;
}
于 2013-10-03T11:55:44.223 に答える