Android How to rotate needle when speed changes?

后端 未结 2 670
渐次进展
渐次进展 2020-12-24 00:09

I have written an application where I have a speedometer with a needle, and I am trying to rotate the needle around its center with th

2条回答
  •  猫巷女王i
    2020-12-24 00:24

    Here is a custom GaugeView I wrote: GaugeView.java

    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.LayoutInflater;
    import android.view.animation.Animation;
    import android.view.animation.Animation.AnimationListener;
    import android.view.animation.RotateAnimation;
    import android.view.animation.Transformation;
    import android.widget.AbsoluteLayout;
    import android.widget.LinearLayout;
    @SuppressWarnings("deprecation")
    
    public class GaugeView extends LinearLayout{
    
    private int gaugeDiameter;      //Gauge radius
    private int gaugeBackground;    //Gauge background resource
    private int needleBackground;   //Needle background resource
    private int needleWidth;        //Needle width
    private int needleHeight;       //Needle height
    private int needleX;            //Needle X position
    private int needleY;            //Needle Y position
    private int needleDeltaX;       //Needle's X position from the centre of gauge
    private int needleDeltaY;       //Needle's Y position from the centre of gauge
    private int deflectTime;        //Animation time when needle deflects to a higher angle
    private int releaseTime;        //Animation time when needle deflects to a lower angle
    private int pivotX;             //Needles X Axis of rotation
    private int pivotY;             //Needles Y Axis of rotation
    private int deltaXAxis;         //Needles new X Axis of rotation
    private int deltaYAxis;         //Needles new Y Axis of rotation
    private float currentValue;     //Current needle value
    private float minValue;         //Minimum needle value
    private float maxValue;         //Maximum needle value
    private float currentAngle;     //Current angular position of needle(Used in rotate animation)
    private float previousAngle;    //To store last known angular position of needle(Used in rotate animation)
    private float minAngle;         //Minimum angle of needle
    private float maxAngle;         //Maximum angle of needle
    private float currentDegrees;   //Current angular position of needle
    
    private boolean animateDeflect; //Enable/Disable rotate animation
    
    NeedleDeflectListener NDL;
    public interface NeedleDeflectListener { 
        /**Called when needle value or angle is changed*/
        public void onDeflect(float angle,float value);
    
        }
    
    /**Register a callback to be invoked when the needle value/angle is changed.*/
    public void setOnNeedleDeflectListener(NeedleDeflectListener eventListener) {
        NDL=eventListener;
        }
    
    private AbsoluteLayout guageBack;
    private LinearLayout gaugeNeedle;
    
    /**Custom view used for creating analog gauges like speedometer*/
    public GaugeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        if(!isInEditMode()){
            LayoutInflater layoutInflater = (LayoutInflater)context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            layoutInflater.inflate(R.layout.gauge_layout,this);
            initView(); 
        }
    
    }
    
    
    private void initView() // Initializes the view
     {
        this.gaugeBackground=R.drawable.gauge_gradient;
        this.needleBackground=R.drawable.needle_gradient;
        this.gaugeDiameter=0;
        this.needleWidth=0;
        this.needleHeight=0;
        this.needleX=0;
        this.needleY=0;
        this.needleDeltaX=0;
        this.needleDeltaY=0;
        this.currentValue=0;
        this.minValue=0;
        this.maxValue=100;
        this.currentAngle=0;
        this.minAngle=0;
        this.maxAngle=360;
        this.deflectTime=0;
        this.releaseTime=0;
        this.pivotX=0;
        this.pivotY=0;
        this.previousAngle=0;
        this.deltaXAxis=0;
        this.deltaYAxis=0;
        this.currentDegrees=0;
        this.animateDeflect=true;
        this.gaugeNeedle=(LinearLayout)findViewById(R.id.gaugeNeedleLay);
        this.guageBack=(AbsoluteLayout) findViewById(R.id.gaugeFrame);
        this.guageBack.setBackgroundResource(gaugeBackground);
        this.gaugeNeedle.setBackgroundResource(needleBackground);
        this.gaugeNeedle.bringToFront();
     }
    
    
    /**Sets a background resource for the gauge*/
    public void setGaugeBackgroundResource(int resID)
     {
        gaugeBackground=resID;
        guageBack.setBackgroundResource(0);
        guageBack.setBackgroundResource(gaugeBackground);
        guageBack.refreshDrawableState();
     }
    
    
    /**Sets the Diameter of the gauge*/
    public void setDiameter(int diameter)
     {
         gaugeDiameter=diameter;
         guageBack.setLayoutParams(new android.widget.LinearLayout.LayoutParams(gaugeDiameter,gaugeDiameter));  
     }
    
    
    /**Sets a background resource for the needle*/
    public void setNeedleBackgroundResource(int resID)
    {
        needleBackground=resID;
        gaugeNeedle.setBackgroundResource(needleBackground);
    }
    
    
    /**Creates a needle at the centre of the gauge.
    
    deltaX: Adjusts needle's X position from the centre of gauge
    deltaY: Adjusts needle's Y position from the centre of gauge*/ public void createNeedle(int width,int height,int deltaX,int deltaY) { this.needleWidth=width; this.needleHeight=height; this.needleDeltaX=deltaX; this.needleDeltaY=deltaY; this.needleX=guageBack.getLeft()+(gaugeDiameter/2)+needleDeltaX-needleWidth/2; this.needleY=guageBack.getTop()+(gaugeDiameter/2)+needleDeltaY; this.pivotX=needleWidth/2; this.pivotY=Math.abs(needleDeltaY); AbsoluteLayout.LayoutParams params = new AbsoluteLayout.LayoutParams(this.needleWidth,this.needleHeight,this.needleX,this.needleY); gaugeNeedle.setLayoutParams(params); } /**Sets a reference background for the gauge*/ public void setReferenceBackground() { guageBack.setBackgroundResource(R.drawable.degrees); } /**Removes the reference background of the gauge*/ public void removeReferenceBackground() { guageBack.setBackgroundResource(this.gaugeBackground); } /**Sets the current needle value*/ public void setCurrentValue(float value) { if(value>maxValue) this.currentValue=maxValue; else if(value360) max_Angle=360; this.minAngle=min_Angle; this.maxAngle=max_Angle; } /**Sets the current needle angle*/ public void setCurrentAngle(float angle) { if(angle>maxAngle) this.currentAngle=maxAngle; else if(anglethis.previousAngle) needleDeflection.setDuration(this.deflectTime); else needleDeflection.setDuration(this.releaseTime); if(!animateDeflect) needleDeflection.setDuration(0); needleDeflection.setFillAfter(true); this.gaugeNeedle.startAnimation(needleDeflection); this.gaugeNeedle.refreshDrawableState(); } /**Sets the needle's animation time
    deflectTime: Time taken by the needle to deflect to a higher value/angle
    releaseTime: Time taken by the needle to deflect to a lower value/angle*/ public void setAnimationTime(int deflectTime,int releaseTime) { this.releaseTime=releaseTime; this.deflectTime=deflectTime; } /**Sets the axis of needle rotation with respect to the centre of gauge*/ public void setDeltaAxis(int deltaX,int deltaY) { this.deltaXAxis=deltaX; this.deltaYAxis=deltaY; this.pivotX=(needleWidth/2)+deltaXAxis; this.pivotY=deltaYAxis; } /**Returns the current needle angle*/ public float getCurrentAngle() { return this.currentDegrees; } /**Returns the Background resource ID of the gauge*/ public int getGaugeBackgroundResource() { return this.gaugeBackground; } /**Returns the Diameter of the gauge*/ public int getDiameter() { return this.gaugeDiameter; } /**Returns the Background resource ID of the needle*/ public int getNeedleBackgroundResource() { return this.needleBackground; } /**Returns the current needle value*/ public float getCurrentValue() { return this.currentValue; } /**Returns the needle width*/ public int getNeedleWidth() { return this.needleWidth; } /**Returns the needle height*/ public int getNeedleHeight() { return this.needleHeight; } /**Returns the X position of needle*/ public int getNeedlePositionX() { return this.needleX; } /**Returns the Y position of needle*/ public int getNeedlePositionY() { return this.needleY; } /**Returns the X axis of rotation of needle*/ public int getNeedleAxisX() { return this.pivotX; } /**Returns the X axis of rotation of needle*/ public int getNeedleAxisY() { return this.pivotY; } /**Returns the minimum needle value*/ public float getMinValue() { return this.minValue; } /**Returns the maximum needle value*/ public float getMaxValue() { return this.maxValue; } /**Returns the minimum needle angle*/ public float getMinAngle() { return this.minAngle; } /**Returns the maximum needle angle*/ public float getMaxAngle() { return this.maxAngle; } /**Returns the needle deflect time*/ public int getDeflectTime() { return this.deflectTime; } /**Returns the needle release time*/ public int getReleaseTime() { return this.releaseTime; } /**Enable/disable needle animation*/ public void setNeedleAnimation(boolean EnableAnimation) { this.animateDeflect=EnableAnimation; } /**Returns needle animation state*/ public boolean getNeedletAnimation() { return this.animateDeflect; } }

    And the gauge_layout.xml layout xml file:

    
    
        
        
    
    

    Implementation example:

    final GaugeView gv=(GaugeView)findViewById(R.id.gaugeView1);
    gv.setBackgroundResource(R.drawable.gaugeback_image);
    gv.setNeedleBackgroundResource(R.drawable.needle_image);
    gv.setDiameter(460);
    gv.createNeedle(50,230,0,-20);
    gv.setAngleRange(45,315);
    

    UPDATE:

    AbsoluteLayout is deprecated. You can replace it with RelativeLayout and some code changes.

提交回复
热议问题