2

因此,我正在玩android並陷入死衚衕。正確處理自定義LinearLayout的自定義屬性

此問題可能與this one有關,因爲它的回答可能是我的問題的一個很好的解決方法,但我對我的代碼失敗的原因感興趣。我可能會對Views有一些嚴重的誤解。

所以,我有這樣的步步高板:

backgammon board with chips stacked on the top and the bottom

我將要上的一舉一動進行動畫,爲此,我需要得到移動芯片的起源和屏幕上的目的地座標。

因此,我必須確定積分的行爲是堆棧,必須在倒置點的底部插入新的視圖,並在下降的頂部插入新的視圖。 因爲任何一點的重力是TOP或BOTTOM取決於它在屏幕上的位置,我能做到這一點得到這個屬性,但它似乎是私人:see this answer in the related post

所以我創建了一個定製的LinearLayout:

<resources> 
<declare-styleable name="PointView"> 
    <attr name="upsideDown" format="boolean" /> 
</declare-styleable> 
</resources> 

它覆蓋的LinearLayout

public class PointView extends LinearLayout { 
    private boolean mUpsideDown = false; 

public PointView(Context context) { 
    super(context); 
} 

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

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

private void init(Context context, AttributeSet attrs, int defStyle) { 

    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PointView); 

    mUpsideDown = a.getBoolean(R.styleable.PointView_upsideDown, false); 
    a.recycle(); 
} 

@Override 
public View getChildAt(int index) { 
    return mUpsideDown ? super.getChildAt(index) : super.getChildAt(super.getChildCount() - index + 1); 
} 

@Override 
public void addView(View child) { 
    if(mUpsideDown) { 
     super.addView(child); 
    } 
    else { 
     super.addView(child, 0); 
    } 
} 
} 

他們包含在我活動的XML是這樣的:

<spacebar.backgammoid.PointView 
        android:orientation="vertical" 
        android:layout_width="0dp" 
        android:layout_height="match_parent" 
        android:background="@drawable/black_point" 
        android:layout_weight="1" 
        android:focusableInTouchMode="false" 
        android:id="@+id/point13" 
        android:weightSum="5" 
        android:clipChildren="false" 
        android:gravity="top" 
        app:upsideDown="true"/> 

現在,當的init()在運行時被調用時,我得到一個異常:

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.resolveLayoutParams()' on a null object reference 

看起來像我的情況下是空的:

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PointView); 

而且我沒有任何線索爲什麼,所以我無法訪問我的自定義屬性upsideDown。

試圖從ATTRS可以訪問屬性:

 attrs.getAttributeBooleanValue(R.styleable.PointView_upsideDown, false); 

它看起來像一個同義詞對我來說,雖然它顯然不是,總是返回true。

任何想法?

預先感謝

[編輯]

異常的堆棧跟蹤:

--------- beginning of crash 
06-23 10:04:34.972 2036-2036/spacebar.backgammoid E/AndroidRuntime﹕ FATAL EXCEPTION: main 
Process: spacebar.backgammoid, PID: 2036 
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.resolveLayoutParams()' on a null object reference 
     at android.view.ViewGroup.resolveLayoutParams(ViewGroup.java:6116) 
     at android.view.ViewGroup.resolveLayoutParams(ViewGroup.java:6116) 
     at android.view.ViewGroup.resolveLayoutParams(ViewGroup.java:6116) 
     at android.view.ViewGroup.resolveLayoutParams(ViewGroup.java:6116) 
     at android.view.ViewGroup.resolveLayoutParams(ViewGroup.java:6116) 
     at android.view.ViewGroup.resolveLayoutParams(ViewGroup.java:6116) 
     at android.view.ViewGroup.resolveLayoutParams(ViewGroup.java:6116) 
     at android.view.ViewGroup.resolveLayoutParams(ViewGroup.java:6116) 
     at android.view.ViewGroup.resolveLayoutParams(ViewGroup.java:6116) 
     at android.view.ViewGroup.resolveLayoutParams(ViewGroup.java:6116) 
     at android.view.ViewGroup.resolveLayoutParams(ViewGroup.java:6116) 
     at android.view.View.setLayoutParams(View.java:11473) 
     at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:273) 
     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:85) 
     at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3055) 
     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2395) 
     at android.app.ActivityThread.access$800(ActivityThread.java:151) 
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) 
     at android.os.Handler.dispatchMessage(Handler.java:102) 
     at android.os.Looper.loop(Looper.java:135) 
     at android.app.ActivityThread.main(ActivityThread.java:5257) 
     at java.lang.reflect.Method.invoke(Native Method) 
     at java.lang.reflect.Method.invoke(Method.java:372) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 

[EDIT 2]

我用芯片填充點編程,填充在Activity的XML中會引發同樣的問題在設計時使用。但是,如果我使用常規的LinearLayouts而不是我的自定義視圖,那麼一切正常,並且沒有錯誤。

<LinearLayout ...> 
    <ImageView ... /> 
</LinearLayout> 

而且,我不知道這是否是相關的,但Android的工作室設計師不允許我在我的PoinView窩瀏覽:

+0

分享您的整個疊層請跟蹤。 –

+0

我把它附加到問題上,謝謝 –

+0

這是完整的堆棧跟蹤嗎?它似乎並沒有在PointView中執行任何代碼。如果您在XML中註釋掉PointView,您的程序是否可以正常運行? –

回答

0

好,我知道它的工作

我的代碼有兩個問題。

  1. 墨菲定律九:自然總是與隱藏缺陷方面: 這是錯誤的

    回報mUpsideDown? super.getChildAt(index):super.getChildAt(super.getChildCount() - index + 1);

我試圖在兒童列表結束後訪問兩個位置。它應該是

super.getChildAt(super.getChildCount() - (index + 1)); 

super.getChildAt(super.getChildCount() - index - 1); 

這是爲異常的原因。在填充我的LinearLayout時,Android正試圖在這個時候膨脹null。

其次,

@Override 
public void addView(View child) { 
    if(mUpsideDown) { 
     super.addView(child); 
    } 
    else { 
     super.addView(child, 0); 
    } 
} 

不工作,不重寫此方法給我預期的行爲,我想Android使用getChildAt()充氣LinearLayouts時,這樣我可以插入兒童觀的常規方式,使他們無論它的方向如何,都堆在頂點。

的辦法,我訪問我的自定義屬性是確定的(這是我的問題的答案,因爲它是制定)

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PointView); 

mUpsideDown = a.getBoolean(R.styleable.PointView_upsideDown, false); 
a.recycle(); 

感謝,@Ravi Thapliyal,您的關注