4

So, I wan't to update an ImageView to change gradients according to some events from the phone gyroscope and Lightsensor. However, at this moment I am trying it out with click events.

I want to set a radial gradient with a center at the click event. I first tried setting the layout background with this in mind and everything worked great. Then I tried changing it for an ImageView (which is the desired visual element in size and position) within the layout and the gradient center gets shifted down and to the right.

Here's the code:

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_seeker);

    RelativeLayout layout = (RelativeLayout) findViewById(R.id.seeker_layout);

    layout.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {

                int location[] = new int[2];
                //measuring location of Image View to try and find correlation to shift
                findViewById(R.id.gradient_indicator).getLocationOnScreen(location);
                int grad_height = findViewById(R.id.gradient_indicator).getMeasuredHeight();
                int grad_width = findViewById(R.id.gradient_indicator).getMeasuredWidth();
                final float pos_x = event.getX();
                final float pos_y = event.getY();
                Toast position = Toast.makeText(getApplicationContext(), "Event Position (" + String.valueOf(pos_x) + "x" + String.valueOf(pos_y) + ")\n Window Dimensions(" + grad_width + "x" + grad_height + ")\n Window Position(" + location[0] + "x" + location[1] + ")", Toast.LENGTH_LONG);
                position.show();

                ShapeDrawable.ShaderFactory shader_factory = new ShapeDrawable.ShaderFactory() {

                    @Override
                    public Shader resize(int width, int height) {
                        RadialGradient radialGradient = new RadialGradient(pos_x, pos_y, 350, 0xff0000ff, 0, Shader.TileMode.MIRROR);
                        return radialGradient;
                    }
                };

                //Set curve radius to equal values in dp as specified in loaded xml shape
                float dp_radius = 5;
                int curve = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp_radius, getResources().getDisplayMetrics());
                float[] r_radii = new float[8];
                Arrays.fill(r_radii,curve);

                //create shape programatically that matches xml one
                RoundRectShape rs = new RoundRectShape(r_radii, null, null);
                ShapeDrawable sd = new ShapeDrawable(rs);
                sd.setShaderFactory(shader_factory);

                ImageView gradient_indicator = (ImageView) findViewById(R.id.gradient_indicator);

                if (Build.VERSION.SDK_INT >= 15) {
                    setBackgroundV15Plus(gradient_indicator, sd);
                } else {
                    setBackgroundV15Minus(gradient_indicator, sd);
                }


            }
            return true;
        }
    });
}
@TargetApi(15)
private void setBackgroundV15Plus(View view, ShapeDrawable sd) {
    view.setBackground(sd);

}

@SuppressWarnings("deprecation")
private void setBackgroundV15Minus(View view, ShapeDrawable sd) {
    view.setBackgroundDrawable(sd);
}

And here's an image of the result I'm getting, I've marked the position of the cursor with a red circle. Displaced Gradient

abbath
  • 2,444
  • 4
  • 28
  • 40
  • 1
    If it was working when used as layout background i will bet if you make the imageview full screen it should work, maybe you need to offset both x,y from the imageview position. Have you noticed the center being sightly displaced to the bottom when used in the layout background? – Nanoc Dec 03 '15 at 16:11
  • The root of the problem seems to be margin or padding set in the xml. It persists if I set margin on the ImageView itself or padding on the Relative View that holds the image. If I bring it to fullscreen there's no problem. I can solve it by substracting the margin pixel from the actual click event. However I was hoping this could be solved more elegantly, perhaps when the Shader resize function gets called. – Mauricio Aguilar Cardenas Dec 03 '15 at 16:32
  • If you dont want the imageview to go full screen that is the only way, in IOS you have a bult-in function that offset the touchevent to a given view, in Android you have to do it manually. Anyway, all your problems are caused by not reading this :) http://stackoverflow.com/questions/29956014/why-should-we-use-xml-layouts – Nanoc Dec 03 '15 at 16:35
  • That post doesn't really comment on the adverse effects of needing to programatically update the gradient/background of an xml shape from events. In fact, I want to conserve aspect ratio, thats why the original shape is defined in xml and 'dp' units. I do get it that Android is making these kind of operatons difficult. – Mauricio Aguilar Cardenas Dec 03 '15 at 16:48

1 Answers1

0

Working solution as Nanoc suggested (its not super elegant but it works):
The way I worked it out is to add margin in the xml ImageView declaration. Then you can access the margin from Java without needing to convert dp-pixel units. Subtract from event position and that'all.
Code for accessing margins:
ImageView gradient_indicator = (ImageView) findViewById(R.id.gradient_indicator); RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) gradient_indicator.getLayoutParams(); int grad_margin_top = lp.topMargin; int grad_margin_left = lp.leftMargin;