7

私は を持っているアプリケーションを作成しspeedometerました。速度の変化に合わせてneedle針を回転させようとしています。center

その角度からインターネットからのダウンロード速度の速度値を計算し、

私の質問は、スピードメーターの中心に針の一端を固定する方法ですか?

角度値を変更して針を回転させる方法は?

私はこのように期待されています

ここに画像の説明を入力

ここで針は中心位置を修正しません 最初の画像中心のように画像の針中心を修正する方法

ここに画像の説明を入力

4

2 に答える 2

16

ここに私が書いたカスタム GaugeView があります: 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);

アップデート:

AbsoluteLayout廃止されました。RelativeLayoutこれをいくつかのコード変更で置き換えることができます。

于 2013-01-09T06:03:11.787 に答える
5

これを行う方法はたくさんあります。あなたを助けるかもしれないいくつかのスレッド:

Android: imageview 内の画像をある角度だけ回転させる

Androidスピードメーター(針ゲージ)

Android ゲージ アニメーションの質問

これは、同様の種類のアニメーションを使用してビンテージ温度計を作成する、私が見つけた優れたチュートリアルです。

http://mindtherobot.com/blog/272/android-custom-ui-making-a-vintage-thermometer/

于 2013-01-09T05:34:20.387 に答える