web-dev-qa-db-ja.com

マルチグラデーションシェイプ

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

alt text

色1から色2への上半分のグラデーションに注目してください。ただし、色3から色4へのグラデーションの下半分があります。1つのグラデーションで図形を作成する方法は知っていますが、図形を2つの半分に分け、2つの異なるグラデーションで1つのシェイプを作成します。

何か案は?

174
Andrew

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

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配列では複数のカラーストップを選択でき、次のフロート配列はそれらのストップの位置を定義します(0から1)。その後、前述のように、これを標準のDrawableとして使用できます。

編集:シナリオでこれを使用する方法を次に示します。次のようなXMLで定義されたButtonがあるとします。

<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度の角度で移動します。

編集:さて、私はもう一つのアイデアがあります、ハハ。現時点ではXMLで動作しますが、Javaのシェイプでも実行できるはずです。それは一種の複雑であり、それを単一の形状に単純化する方法があると思いますが、これは私が今持っているものです:

green_horizo​​ntal_gradient.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>

half_overlay.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>

layer_list.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>

test.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にインライン化され、この余分なファイルが不要になると確信していますが、その方法はわかりません。しかし、大丈夫、そのようなハッキングの部分はlayer_list XMLファイルにあります。緑のグラデーションを下のレイヤーとして配置し、次に半分のオーバーレイを2番目のレイヤーとして配置し、上から50dpオフセットします。ただし、この数値は常にビューサイズの半分であり、固定の50dpではないことが必要です。ただし、パーセンテージを使用できるとは思わない。そこから、layer.list.xmlファイルを背景として使用して、test.xmlレイアウトにTextViewを挿入しました。高さを100dp(オーバーレイのオフセットのサイズの2倍)に設定すると、次のようになります。

alt text

多田!

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

layer_list.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つの編集

さて、コンテナの高さに合わせてこのレイヤードロウアブルを手動で更新する方法を見つけました。詳細な説明は here です。このコードは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);
            }
        });

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

376
kcoppock

Layer-listを使用して、xmlのグラデーションシェイプを階層化できます。次のデフォルト状態のボタンを想像してください。2番目の項目は半透明です。一種のケラレを追加します。 (カスタム定義の色を許してください。)

<!-- Normal state. -->
<item>
    <layer-list>
        <item>  
            <shape>
                <gradient 
                    Android:startColor="@color/grey_light"
                    Android:endColor="@color/grey_dark"
                    Android:type="linear"
                    Android:angle="270"
                    Android:centerColor="@color/grey_mediumtodark" />
                <stroke
                    Android:width="1dp"
                    Android:color="@color/grey_dark" />
                <corners
                    Android:radius="5dp" />
            </shape>
        </item>
        <item>  
            <shape>
                <gradient 
                    Android:startColor="#00666666"
                    Android:endColor="#77666666"
                    Android:type="radial"
                    Android:gradientRadius="200"
                    Android:centerColor="#00666666"
                    Android:centerX="0.5"
                    Android:centerY="0" />
                <stroke
                    Android:width="1dp"
                    Android:color="@color/grey_dark" />
                <corners
                    Android:radius="5dp" />
            </shape>
        </item>
    </layer-list>
</item>
27
LordParsley

Xmlシェイプのみを使用して実行できます。次のように、layer-listとネガティブパディングを使用します。

    <layer-list>

        <item>
            <shape>
                <solid Android:color="#ffffff" />

                <padding Android:top="20dp" />
            </shape>
        </item>

        <item>
            <shape>
                <gradient Android:endColor="#ffffff" Android:startColor="#efefef" Android:type="linear" Android:angle="90" />

                <padding Android:top="-20dp" />
            </shape>
        </item>

    </layer-list>
4
konmik

緑のグラデーションの不透明な不透明度を持つ別の画像の上に、ハイライトの不透明度がほぼ透明なグラデーションを別の画像の上に重ねようとしましたか?

1
Greg D

この方法を試してから、必要なことをすべて実行できます。
stackに似ているため、最初に来るアイテムと最後に来るアイテムに注意してください。

<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:Android="http://schemas.Android.com/apk/res/Android">
<item Android:right="50dp" Android:start="10dp" Android:left="10dp">
    <shape
        xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:shape="rectangle">
        <corners Android:radius="3dp" />
        <solid Android:color="#012d08"/>
    </shape>
</item>
<item Android:top="50dp">
    <shape Android:shape="rectangle">
        <solid Android:color="#7c4b4b" />
    </shape>
</item>
<item Android:top="90dp" Android:end="60dp">
    <shape Android:shape="rectangle">
        <solid Android:color="#e2cc2626" />
    </shape>
</item>
<item Android:start="50dp" Android:bottom="20dp" Android:top="120dp">
    <shape Android:shape="rectangle">
        <solid Android:color="#360e0e" />
    </shape>
</item>
1
Khalid Ali