Правильный доступ к пользовательским атрибутам пользовательского LinearLayout

Так что я играюсь с андроидом и зашел в тупик.

Этот вопрос может быть связан с этим, поскольку его ответ может быть хорошим решением моей проблемы, но Меня интересует причина, по которой мой код не работает. У меня могут быть некоторые серьезные заблуждения о представлениях.

Итак, у меня есть вот такая доска для игры в нарды:

доска для игры в нарды со сложенными сверху и снизу фишками

Я хочу выполнять анимацию при каждом движении, и для этого мне нужно получить на экране координаты начала и места назначения движущегося чипа.

Поэтому я должен быть уверен, что точки ведут себя как стопки, новые представления должны быть вставлены в нижнюю часть перевернутых точек и в верхнюю часть перевернутых. Поскольку гравитация любой точки ВЕРХ или НИЗ в зависимости от ее положения на экране, я мог бы сделать это, получив этот атрибут, но он кажется частным: см. этот ответ в соответствующем сообщении

Поэтому я создал собственный 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

Похоже, мой контекст имеет значение null в:

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

И я понятия не имею, почему, и поэтому я не могу получить доступ к своему пользовательскому атрибуту вверх ногами.

Попытка получить доступ к свойству из 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)

[ИЗМЕНИТЬ 2]

Я программно заполнял точки чипами, заполнение XML-файла Activity вызывает то же исключение во время разработки.

<spacebar.backgammoid.PointView ...>
    <ImageView ... />
</spacebar.backgammoid.PointView>

Тем не менее, если я использую обычные LinearLayouts вместо своего пользовательского представления, все работает нормально, и ошибки нет.

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

Кроме того, я не знаю, актуально ли это, но дизайнер android-studio не позволяет мне вкладывать представления в мой PoinView:


person Luis Sieira    schedule 23.06.2015    source источник
comment
Поделитесь полной трассировкой стека, пожалуйста.   -  person Ravi K Thapliyal    schedule 23.06.2015
comment
Я добавил это к вопросу, спасибо   -  person Luis Sieira    schedule 23.06.2015
comment
Это полная трассировка стека? Похоже, внутри PointView не выполняется какой-либо код. Будет ли ваша программа работать нормально, если вы закомментируете PointView в XML?   -  person Ravi K Thapliyal    schedule 23.06.2015
comment
Да, если я использую обычные LinearLayouts вместо своего пользовательского представления, все работает нормально.   -  person Luis Sieira    schedule 23.06.2015
comment
Я добавил несколько новых [edit 2]   -  person Luis Sieira    schedule 23.06.2015
comment
Я думаю, что все это связано с LayoutInflater, но я не могу понять, как его использовать. Я единственный, кому это имя напоминает экономическую инфляцию?   -  person Luis Sieira    schedule 23.06.2015


Ответы (1)


Хорошо, у меня это работает

В моем коде есть две проблемы.

  1. Девятый закон Мерфи: природа всегда на стороне скрытого недостатка: это просто неправильно

    вернуть mUpsideDown ? super.getChildAt(index): super.getChildAt(super.getChildCount() - index + 1);

Я пытался получить доступ к двум позициям после окончания списка детей. Так должно быть

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

or

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

Это и было причиной исключения. В этот момент Android пытался раздуть значение null при заполнении моего LinearLayout.

Во-вторых,

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

Не работало, не переопределение этого метода дает мне ожидаемое поведение, я думаю, андроид использует getChildAt() при раздувании LinearLayouts, и поэтому я могу вставлять дочерние представления обычным способом, чтобы они складывались в верхней части точки независимо от ее ориентации.

То, как я обращался к своим пользовательским атрибутам, было в порядке (что является ответом на мой вопрос, как он был сформулирован)

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

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

Спасибо, @Ravi Thapliyal, за проявленный интерес.

person Luis Sieira    schedule 23.06.2015