2014-01-16 39 views
0

我已經搜索了幾個小時,但找不到一個解決方案。我試圖創建一個自定義的TextView,如果它是數字,它將動畫值。但是,即使在開始第一個值之前,我也會遇到異常。我希望你能幫忙。在Android中自定義TextView錯誤

這裏是我的代碼:

import android.animation.ValueAnimator; 
import android.content.Context; 
import android.graphics.Canvas; 
import android.util.AttributeSet; 
import android.widget.TextView; 

public class AnimatedValueTextView extends TextView { 
    private static final int DURATION = 900; 
    private float actualValue; 
    private ValueAnimator animator; 

    public AnimatedValueTextView(Context context) { 
     super(context); 
     init(); 
    } 

    public AnimatedValueTextView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     init(); 
    } 

    public AnimatedValueTextView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
     init(); 
    } 


    private void init() 
    { 
     actualValue = 0; 
     animator = new ValueAnimator(); 

     animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
      @Override 
      public void onAnimationUpdate(ValueAnimator valueAnimator) { 
       setText(valueAnimator.getAnimatedValue().toString()); 
       actualValue = (Float)valueAnimator.getAnimatedValue(); 
      } 
     }); 

     animator.setDuration(DURATION); 
    } 

    @Override 
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { 
     super.onTextChanged(text, start, lengthBefore, lengthAfter); 

     boolean validValue = true; 
     float newValue = 0; 

     try { 
      newValue = Float.parseFloat(this.getText().toString()); 
     } 

     catch (Exception e) 
     { 
      validValue = false; 
     } 

     if(validValue) 
     { 
      if(animator == null) 
      { 
       init(); 
      } 

      animator.cancel(); 
      animator.setFloatValues(actualValue, newValue); 
      animator.start(); 
     } 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     super.onDraw(canvas); 
    } 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
    } 
} 

我的XML

<com.---.-------.AnimatedValueTextView 
      android:id="@+id/actualPressure" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      style="@style/FunkyTextBig" 
      android:paddingLeft="2dp" 
      android:text="1043"/> 

而且logcat的

01-16 09:55:14.954 5085-5085/com.---.----- E/AndroidRuntime﹕ FATAL EXCEPTION: main 
    android.view.InflateException: Binary XML file line #18: Error inflating class com.---.-----.AnimatedValueTextView 
      at android.view.LayoutInflater.createView(LayoutInflater.java:620) 
      at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:696) 
      at android.view.LayoutInflater.rInflate(LayoutInflater.java:755) 
      at android.view.LayoutInflater.rInflate(LayoutInflater.java:758) 
      at android.view.LayoutInflater.inflate(LayoutInflater.java:492) 
      at android.view.LayoutInflater.inflate(LayoutInflater.java:397) 
      at com.---.-----.ForecastFragment.onCreateView(ForecastFragment.java:70) 
      at android.app.Fragment.performCreateView(Fragment.java:1695) 
      at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:885) 
      at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1057) 
      at android.app.BackStackRecord.run(BackStackRecord.java:682) 
      at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1435) 
      at android.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:474) 
      at android.support.v13.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:167) 
      at android.support.v4.view.ViewPager.populate(ViewPager.java:1068) 
      at android.support.v4.view.ViewPager.populate(ViewPager.java:914) 
      at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1436) 
      at android.view.View.measure(View.java:15848) 
      at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:728) 
      at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:477) 
      at android.view.View.measure(View.java:15848) 
      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5008) 
      at android.widget.FrameLayout.onMeasure(FrameLayout.java:310) 
      at android.view.View.measure(View.java:15848) 
      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5008) 
      at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1404) 
      at android.widget.LinearLayout.measureVertical(LinearLayout.java:695) 
      at android.widget.LinearLayout.onMeasure(LinearLayout.java:588) 
      at android.view.View.measure(View.java:15848) 
      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5008) 
      at android.widget.FrameLayout.onMeasure(FrameLayout.java:310) 
      at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2189) 
      at android.view.View.measure(View.java:15848) 
      at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1905) 
      at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1104) 
      at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1284) 
      at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1004) 
      at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5481) 
      at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749) 
      at android.view.Choreographer.doCallbacks(Choreographer.java:562) 
      at android.view.Choreographer.doFrame(Choreographer.java:532) 
      at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735) 
      at android.os.Handler.handleCallback(Handler.java:730) 
      at android.os.Handler.dispatchMessage(Handler.java:92) 
      at android.os.Looper.loop(Looper.java:137) 
      at android.app.ActivityThread.main(ActivityThread.java:5103) 
      at java.lang.reflect.Method.invokeNative(Native Method) 
      at java.lang.reflect.Method.invoke(Method.java:525) 
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737) 
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
      at dalvik.system.NativeStart.main(Native Method) 
    Caused by: java.lang.reflect.InvocationTargetException 
      at java.lang.reflect.Constructor.constructNative(Native Method) 
      at java.lang.reflect.Constructor.newInstance(Constructor.java:417) 
      at android.view.LayoutInflater.createView(LayoutInflater.java:594) 
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:696) 
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:755) 
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:758) 
            at android.view.LayoutInflater.inflate(LayoutInflater.java:492) 
            at android.view.LayoutInflater.inflate(LayoutInflater.java:397) 
            at com.---.-----.ForecastFragment.onCreateView(ForecastFragment.java:70) 
            at android.app.Fragment.performCreateView(Fragment.java:1695) 
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:885) 
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1057) 
            at android.app.BackStackRecord.run(BackStackRecord.java:682) 
            at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1435) 
            at android.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:474) 
            at android.support.v13.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:167) 
            at android.support.v4.view.ViewPager.populate(ViewPager.java:1068) 
            at android.support.v4.view.ViewPager.populate(ViewPager.java:914) 
            at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1436) 
            at android.view.View.measure(View.java:15848) 
            at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:728) 
            at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:477) 
            at android.view.View.measure(View.java:15848) 
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5008) 
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:310) 
            at android.view.View.measure(View.java:15848) 
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5008) 
            at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1404) 
            at android.widget.LinearLayout.measureVertical(LinearLayout.java:695) 
            at android.widget.LinearLayout.onMeasure(LinearLayout.java:588) 
            at android.view.View.measure(View.java:15848) 
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5008) 
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:310) 
            at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2189) 
            at android.view.View.measure(View.java:15848) 
            at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1905) 
            at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1104) 
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1284) 
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1004) 
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5481) 
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749) 
            at android.view.Choreographer.doCallbacks(Choreographer.java:562) 
            at android.view.Choreographer.doFrame(Choreographer.java:532) 
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735) 
            at android.os.Handler.handleCallback(Handler.java:730) 
            at android.os.Handler.dispatchMessage(Handler.java:92) 
            at android.os.Looper.loop(Looper.java:137) 
            at android.app.ActivityThread.main(ActivityThread.java:5103) 
            at java.lang.reflect.Method.invokeNative(Native Method) 
            at java.lang.reflect.Method.invoke(Method.java:525) 
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737) 
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
            at dalvik.system.NativeStart.main(Native Method) 
    Caused by: java.lang.StackOverflowError 
      at java.lang.RealToString.floatToString(RealToString.java:126) 
      at java.lang.Float.toString(Float.java:322) 
      at java.lang.Float.toString(Float.java:310) 

而且所使用的樣式:

<style name="FunkyTextBig" parent="@android:style/TextAppearance"> 
     <item name="android:textColor">#eaf1f7</item> 
     <item name="android:textStyle">bold</item> 
     <item name="android:shadowColor">#000000</item> 
     <item name="android:shadowRadius">13</item> 
     <item name="android:textSize">45sp</item> 
     <item name="android:shadowDx">0</item> 
     <item name="android:shadowDy">0</item> 
    </style> 

    <style name="FunkyTextMedium" parent="@style/FunkyTextBig"> 
     <item name="android:textSize">22sp</item> 
    </style> 
+0

哪個版本的android有設備在哪裏測試它? – Blackbelt

+0

它是4.3版本,我正在爲4.0.4和更新版本開發 – Sulby

+0

您可以發佈樣式嗎? – Blackbelt

回答

1

另一種很好的解決方案未覆蓋onTextChanged方法,以及具有兩種方法的setText:一個公共的一個會觸發動畫,而私人會在沒有動畫的情況下改變數值:

private void init(){ 
    actualValue = 0; 
    animator = new ValueAnimator(); 
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
     @Override 
     public void onAnimationUpdate(ValueAnimator valueAnimator) { 
      setTextInternal(valueAnimator.getAnimatedValue().toString()); 
      actualValue = (Float)valueAnimator.getAnimatedValue(); 
     } 
    }); 

    animator.setDuration(DURATION); 
} 


public void setNumber(float newValue){ 
    animator.cancel(); 
    animator.setFloatValues(actualValue, newValue); 
    animator.start(); 
} 

public void setText(String txt){ 
    try { 
     float newValue = Float.parseFloat(txt); 
     setNumber(newValue); 
    }catch (Exception e){ 
     super.setText(txt); 
    } 
} 


private void setTextInternal(String txt){ 
    super.setText(txt); 
} 
+0

謝謝。我會毫不猶豫地嘗試你的解決方案 – Sulby

0

在您的onTextChanged方法中,您將啓動animator,然後再調用setText(),這又會再次觸發onTextChanged,這會一直持續下去,直到虛擬機已滿足爲止。

如果您改變onTextChanged方法如下,它的工作原理:

@Override 
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { 
    super.onTextChanged(text, start, lengthBefore, lengthAfter); 
    if (animator != null && (animator.isStarted() || animator.isRunning())) 
     return; 

    // rest as above 
+0

有沒有一種方法來覆蓋setText,所以我可以使用OnTextChanged? – Sulby

+0

用解決方案編輯了我的答案 – Thrakbad

1

,因爲你是循環的文本設置您收到此錯誤。

1)onTextChanged被調用來保存初始值

2)在onTextChanged的代碼開始動畫,並在每一步調用的setText(這將自動調用onTextChanged)

3)本onTextChanged將取消動畫並重新開始。

的解決方案是通過標誌來控制onTextChanged的調用,添加其它監聽到動畫:

animator.addListener(new Animator.AnimatorListener(){ 
    public void onAnimationStart(Animator animation) { 
     isAnimating = true; 
    } 
    public void onAnimationEnd(Animator animation) { 
     isAnimating = false; 
    } 
    public void onAnimationRepeat(Animator animation) {} 
    public void onAnimationCancel(Animator animation) {} 
}) 


@Override 
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { 
    if (isAnimating) return; 
    super.onTextChanged(text, start, lengthBefore, lengthAfter); 

    ... 
} 
+0

在動畫結束後,您仍然必須重置isAnimating,否則它只會運行一次。 – Thrakbad

相關問題