Gradient Radius as percentage of screen size

前端 未结 5 1747
南方客
南方客 2020-12-08 13:56

I\'m trying to create a shape drawable with radial gradient background, with radius that will adjust to the screen size (take a look at the relevant documentation).

相关标签:
5条回答
  • 2020-12-08 14:01

    From what I´ve tested, the % does work, but not as you expected.
    First of all

    android:gradientRadius="50"
    

    seems to take the value as pixels 50px

    android:gradientRadius="50%"
    

    is converted as if 50% = 0.5 px, try

    android:gradientRadius="5000%"
    

    and you will see a 50px radius.
    Using %p has a similar result. Obviously this is something I hope will be changed in the future, because it does not have much use as it is. Usually XML ShapeDrawable resources adapt their size to some external container, in this case gradientRadius is setting the size regardless of the container.

    0 讨论(0)
  • 2020-12-08 14:01

    I ended up creating a custom View with following overriden onDraw method:

    @Override
    protected void onDraw(Canvas canvas) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    
        int maxSize = Math.max(getHeight(), getWidth());
        RadialGradient gradient = new RadialGradient(
                getWidth()/2,
                getHeight()/2,
                maxSize, 
                new int[] {Color.RED, Color.BLACK},
                new float[] {0, 1}, 
                android.graphics.Shader.TileMode.CLAMP);
    
        paint.setDither(true);
        paint.setShader(gradient);
    
        canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
    }
    

    In your layout just add the View:

    <yourpackage.GradientView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    

    Of course it would be possible to create attributes for the View, eg. color, percentage to allow customization via XML.

    0 讨论(0)
  • 2020-12-08 14:03

    It's impossible to set a shape corner radius expressed in percentage in a drawable xml.

    0 讨论(0)
  • 2020-12-08 14:13

    Note that gradientRadius percentages do work in Lollipop. But if you have to support pre-Lollipop I expanded upon @marnaish's answer adding XML attributes. My gradientRadius is defined as a percentage of the parent view's width:

    public class RadialGradientView extends View {
        private final int endColor;
        private final int startColor;
        private final float gradientRadiusWidthPercent;
        private final float centerY;
        private final float centerX;
        private Paint paint;
    
        public RadialGradientView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RadialGradientView, 0, 0);
    
            startColor = a.getColor(R.styleable.RadialGradientView_startColor, Color.RED);
            endColor = a.getColor(R.styleable.RadialGradientView_endColor, Color.BLACK);
            gradientRadiusWidthPercent = a.getFloat(R.styleable.RadialGradientView_gradientRadiusWidthPercent, 1);
            centerX = a.getFloat(R.styleable.RadialGradientView_centerX, .5f);
            centerY = a.getFloat(R.styleable.RadialGradientView_centerY, .5f);
    
            a.recycle();
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
            int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
    
            paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            RadialGradient gradient = new RadialGradient(
                    parentWidth*centerX,
                    parentHeight*centerY,
                    parentWidth*gradientRadiusWidthPercent,
                    new int[] {startColor, endColor},
                    null,
                    android.graphics.Shader.TileMode.CLAMP);
    
            paint.setDither(true);
            paint.setShader(gradient);
    
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
        }
    
    }
    

    In attrs.xml:

    <declare-styleable name="RadialGradientView">
        <attr name="startColor" format="color|reference"/>
        <attr name="endColor" format="color|reference"/>
        <attr name="gradientRadiusWidthPercent" format="float"/>
        <attr name="centerX" format="float"/>
        <attr name="centerY" format="float"/>
    </declare-styleable>
    

    Unfortunately you can't create an XML drawable from a custom class, so you can't set it as a View's android:background. The workaround is to use a FrameLayout to layer it as the background.

    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="100dp">
    
        <com.RadialGradientView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:centerX=".3"
            app:centerY=".5"
            app:endColor="#0f0"
            app:startColor="#f00"
            app:gradientRadiusWidthPercent=".5"
            />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="What's up world?"/>
    </FrameLayout>
    
    0 讨论(0)
  • 2020-12-08 14:15

    You could create a shape drawable at runtime similiar to this post https://stackoverflow.com/a/4943888/604504

    This way you could calculate the percentage after retrieving the screen size.

    0 讨论(0)
提交回复
热议问题