マルチグラデーションシェイプ 質問する

マルチグラデーションシェイプ 質問する

次の画像のような形状を作成したいと思います。

代替テキスト

上半分は色 1 から色 2 へのグラデーションですが、下半分は色 3 から色 4 へのグラデーションになっています。単一のグラデーションで図形を作成する方法はわかっていますが、図形を 2 つに分割して、2 つの異なるグラデーションを持つ 1 つの図形を作成する方法がわかりません。

何か案は?

ベストアンサー1

XMLでは(少なくともAndroidでは)これを行うことはできないと思いますが、良い解決策が投稿されているのを見つけました。ここそれはとても助かります!

ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() {
    @Override
    public Shader resize(int width, int height) {
        LinearGradient lg = new LinearGradient(0, 0, width, height,
            new int[]{Color.GREEN, Color.GREEN, Color.WHITE, Color.WHITE},
            new float[]{0,0.5f,.55f,1}, Shader.TileMode.REPEAT);
        return lg;
    }
};

PaintDrawable p=new PaintDrawable();
p.setShape(new RectShape());
p.setShaderFactory(sf);

基本的に、int 配列を使用すると複数のカラー ストップを選択でき、次の float 配列はそれらのストップが配置される場所 (0 から 1) を定義します。その後、前述のように、これを標準の Drawable として使用できます。

編集: これをシナリオで使用する方法は次のとおりです。次のように XML で定義されたボタンがあるとします。

<Button
    android:id="@+id/thebutton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Press Me!"
    />

次に、onCreate() メソッドに次のようなコードを追加します。

Button theButton = (Button)findViewById(R.id.thebutton);
ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() {
    @Override
    public Shader resize(int width, int height) {
        LinearGradient lg = new LinearGradient(0, 0, 0, theButton.getHeight(),
            new int[] { 
                Color.LIGHT_GREEN, 
                Color.WHITE, 
                Color.MID_GREEN, 
                Color.DARK_GREEN }, //substitute the correct colors for these
            new float[] {
                0, 0.45f, 0.55f, 1 },
            Shader.TileMode.REPEAT);
         return lg;
    }
};
PaintDrawable p = new PaintDrawable();
p.setShape(new RectShape());
p.setShaderFactory(sf);
theButton.setBackground((Drawable)p);

現時点ではテストできません。これは私の頭の中で考えたコードですが、基本的には必要な色を置き換えるか、ストップを追加するだけです。基本的に、私の例では、ライトグリーンから始まり、中央の少し手前で白にフェードし (急激な遷移ではなくフェードを与えるため)、45% から 55% の間で白からミッドグリーンにフェードし、55% から最後までミッドグリーンからダークグリーンにフェードします。これは、あなたの形とまったく同じようには見えないかもしれませんが (現時点では、これらの色をテストする方法がありません)、これを変更してあなたの例を再現することができます。

編集: また、は0, 0, 0, theButton.getHeight()グラデーションの x0、y0、x1、y1 座標を指します。つまり、基本的には x = 0 (左側)、y = 0 (上部) から始まり、x = 0 (垂直グラデーションが必要なので、左から右への角度は必要ありません)、y = ボタンの高さまで伸びます。つまり、グラデーションはボタンの上部からボタンの下部まで 90 度の角度で進みます。

編集: わかりました。もう 1 つ、うまくいくアイデアがあります。笑。今のところ XML で動作しますが、Java の図形でも実行できるはずです。少し複雑で、1 つの図形に単純化する方法があると思いますが、今のところはこれです。

緑の水平グラデーション.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >
    <corners
        android:radius="3dp"
        />
    <gradient
        android:angle="0"
        android:startColor="#FF63a34a"
        android:endColor="#FF477b36"
        android:type="linear"
        />    
</shape>

ハーフオーバーレイ.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >
    <solid
        android:color="#40000000"
        />
</shape>

レイヤーリスト.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <item
        android:drawable="@drawable/green_horizontal_gradient"
        android:id="@+id/green_gradient"
        />
    <item
        android:drawable="@drawable/half_overlay"
        android:id="@+id/half_overlay"
        android:top="50dp"
        />
</layer-list>

テスト.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center"
    >
    <TextView
        android:id="@+id/image_test"
        android:background="@drawable/layer_list"
        android:layout_width="fill_parent"
        android:layout_height="100dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:gravity="center"
        android:text="Layer List Drawable!"
        android:textColor="@android:color/white"
        android:textStyle="bold"
        android:textSize="26sp"     
        />
</RelativeLayout>

わかりました。基本的には、水平方向の緑のグラデーションのシェイプ グラデーションを XML で作成しました。角度は 0 度に設定され、上部の領域の左側の緑から右側の緑へと変化します。次に、半透明のグレーのシェイプ レクタングルを作成しました。これをレイヤー リスト XML にインライン化して、この追加ファイルを不要にできると確信していますが、方法がわかりません。では、次に、レイヤー リスト XML ファイルでハッキーな部分が登場します。緑のグラデーションを一番下のレイヤーとして配置し、半分のオーバーレイを上から 50 dp オフセットした 2 番目のレイヤーとして配置します。もちろん、この数値は常にビュー サイズの半分にし、固定の 50 dp にはしたくないでしょう。ただし、パーセンテージは使用できないと思います。そこから、レイヤー リスト .xml ファイルを背景として使用して、TextView を test.xml レイアウトに挿入しました。高さを 100dp (オーバーレイのオフセットの 2 倍のサイズ) に設定すると、次のようになります。

代替テキスト

じゃーん!

もう一つの編集: 図形をレイヤー リスト描画可能ファイルにアイテムとして埋め込むだけでよいことに気付きました。つまり、3 つの個別の XML ファイルはもう必要ありません。次のように組み合わせて同じ結果を得ることができます。

レイヤーリスト.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <item>
        <shape
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:shape="rectangle"
            >
            <corners
                android:radius="3dp"
                />
            <gradient
                android:angle="0"
                android:startColor="#FF63a34a"
                android:endColor="#FF477b36"
                android:type="linear"
                />    
        </shape>
    </item>
    <item
        android:top="50dp" 
        >
        <shape
            android:shape="rectangle"
            >
            <solid
                android:color="#40000000"
                />
        </shape>            
    </item>
</layer-list>

この方法では、好きなだけアイテムを重ねることができます。Java を使ってもっと多様な結果が得られるかどうか、いろいろ試してみたいと思います。

これが最後の編集になると思います...: わかりました。次のように、Java を通じて位置を修正することができます。

    TextView tv = (TextView)findViewById(R.id.image_test);
    LayerDrawable ld = (LayerDrawable)tv.getBackground();
    int topInset = tv.getHeight() / 2 ; //does not work!
    ld.setLayerInset(1, 0, topInset, 0, 0);
    tv.setBackgroundDrawable(ld);

しかし、これは TextView が描画されるまで測定できないという、さらに別の厄介な問題を引き起こします。これをどのように実現できるかはまだよくわかりませんが、topInset に手動で数値を挿入すると機能します。

嘘をついた、もう1つ編集

さて、このレイヤーの描画可能オブジェクトを手動で更新してコンテナの高さに合わせる方法を見つけました。詳しい説明はこここのコードは onCreate() メソッドに記述する必要があります。

final TextView tv = (TextView)findViewById(R.id.image_test);
        ViewTreeObserver vto = tv.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                LayerDrawable ld = (LayerDrawable)tv.getBackground();
                ld.setLayerInset(1, 0, tv.getHeight() / 2, 0, 0);
            }
        });

これで完了です!ふう!:)

おすすめ記事