2013-01-09 93 views
6

我已經寫了一個應用程序,其中有一個speedometerneedle,我試圖圍繞其轉速變化的center旋轉針。Android速度變化時如何旋轉針頭?

我計算下載速度的速度值從互聯網從這個角度也測量,

我的問題是如何解決在車速表中央的針一端?

如何通過改變角度值來旋轉針頭?

我預計這樣的

enter image description here

這裏的針不能修復中心的地位如何修復圖像的針中心像第一圖像 中心

enter image description here

+0

[This](http://stackoverflow.com/questions/8981845/androidrotate-image-in-imageview-by-an-angle)可能會有所幫助。 – ChiefTwoPencils

+0

發佈您的動畫代碼。因爲當你創建旋轉動畫時,pivoteX和piviteY的值會變成錯誤的。 – Raj

+0

我剛剛創建了一個速度計的背景圖像,並在該圖像上設置了一個圖像視圖指針..如何在中心設置指針? – NagarjunaReddy

回答

13

這是一個自定義的GaugeView I寫道: 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. 
<br> <b>deltaX</b>: Adjusts needle's X position from the centre of gauge 
<br> <b>deltaY</b>: 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(value<minValue) 
     this.currentValue=minValue; 
    else 
     this.currentValue=value; 

    this.currentAngle=(((this.currentValue-this.minValue)*(this.maxAngle-this.minAngle)) 
              /(this.maxValue-this.minValue))+this.minAngle; 
    setCurrentAngle(this.currentAngle); 

} 

/**Sets the needle value range*/ 
public void setValueRange(float min_Value,float max_Value) 
{ 
    this.minValue=min_Value; 
    this.maxValue=max_Value; 

} 

/**Sets the needle angle range (0-360)*/ 
public void setAngleRange(float min_Angle,float max_Angle) 
{ 
    if(min_Angle<0) 
     min_Angle=0; 
    if(max_Angle>360) 
     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(angle<minAngle) 
     this.currentAngle=minAngle; 
    else 
     this.currentAngle=angle; 


    RotateAnimation needleDeflection=new RotateAnimation(this.previousAngle, this.currentAngle,this.pivotX,this.pivotY){ 
     protected void applyTransformation(float interpolatedTime,Transformation t) { 
      currentDegrees=previousAngle+(currentAngle-previousAngle)*interpolatedTime; 
      currentValue=(((currentDegrees-minAngle)*(maxValue-minValue))/(maxAngle-minAngle))+minValue; 
      if(NDL!=null) 
       NDL.onDeflect(currentDegrees,currentValue); 
      super.applyTransformation(interpolatedTime, t); 
     } 

    }; 

    needleDeflection.setAnimationListener(new AnimationListener() {@Override 
     public void onAnimationStart(Animation arg0) {}@Override 
     public void onAnimationRepeat(Animation arg0) {}@Override 
     public void onAnimationEnd(Animation arg0) {previousAngle=currentAngle;}}); 


    if(currentAngle>this.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 
<br> <b>deflectTime</b>: Time taken by the needle to deflect to a higher value/angle 
<br> <b>releaseTime</b>: 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; 

} 

} 

而且gauge_layout.xml佈局xml文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" > 
<AbsoluteLayout 
    android:id="@+id/gaugeFrame" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:scaleType="fitXY" > 
    <LinearLayout 
     android:id="@+id/gaugeNeedleLay" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:gravity="center" 
     android:orientation="vertical" 
     android:scaleType="fitXY" > 
    </LinearLayout> 
</AbsoluteLayout></LinearLayout> 

實現的例子:

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是棄用。您可以用RelativeLayout替換它,並更改一些代碼。

+0

從這我越來越forceclose。在這個drawable中,gauge_background的目的是什麼,needle_background和degrees可以解釋什麼? – NagarjunaReddy

+0

'gaugeBackground'是包含車速表值和皮膚的'drawable'。 'needle_background'是包含針的圖像的'drawable'。請參閱最新的答案。 – JiTHiN

+0

'E/AndroidRuntime(622):了java.lang.RuntimeException:無法實例活動ComponentInfo {com.gaugemeter/com.gaugemeter.MainActivity}:java.lang.InstantiationException:不能實例類com.gaugemeter.MainActivity;沒有空的構造函數'運行此代碼面臨這個錯誤.... – NagarjunaReddy