2013-09-27 4 views
2

Я пытаюсь реализовать проверяемую линейную компоновку, я уже выполняю отмеченный элемент, но теперь onclick и onLongClick его не работают, если бы какие-либо идеи, как я могу реализовать это поведение.Android Checkable LinearLayout states

  • если бесконтрольно & & OnLongClick = проверить
  • если флажок & & OnClick = снимите флажок
  • если проверено & & onLongClick = снимите флажок
  • если незарегистрированный & & OnClick = super.performClick()

Мой проверяемый LinearLayout

public class CheckableLinearLayout extends LinearLayout implements Checkable { 

/** 
* Interface definition for a callback to be invoked when the checked state 
* of this View is changed. 
*/ 
public static interface OnCheckedChangeListener { 

    /** 
    * Called when the checked state of a compound button has changed. 
    * 
    * @param checkableView 
    *   The view whose state has changed. 
    * @param isChecked 
    *   The new checked state of checkableView. 
    */ 
    void onCheckedChanged(View checkableView, boolean isChecked); 
} 

private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked }; 

private boolean mChecked = false; 

private OnCheckedChangeListener mOnCheckedChangeListener; 

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

public boolean isChecked() { 
    return mChecked; 
} 

public void setChecked(boolean b) { 
    if (b != mChecked) { 
     mChecked = b; 
     refreshDrawableState(); 

     if (mOnCheckedChangeListener != null) { 
      mOnCheckedChangeListener.onCheckedChanged(this, mChecked); 
     } 
    } 
} 

public void toggle() { 
    setChecked(!mChecked); 
} 

@Override 
public int[] onCreateDrawableState(int extraSpace) { 
    final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 
    if (isChecked()) { 
     mergeDrawableStates(drawableState, CHECKED_STATE_SET); 
    } 
    return drawableState; 
} 

/** 
* Register a callback to be invoked when the checked state of this view 
* changes. 
* 
* @param listener 
*   the callback to call on checked state change 
*/ 
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) { 
    mOnCheckedChangeListener = listener; 
} 

@Override 
public boolean performLongClick() { 
    toggle(); 
    return super.performLongClick(); 
} 

@Override 
public boolean performClick() { 

    if (isChecked()) { 
     toggle(); 
     return false; 
    } else 
     return super.performClick(); 
} 

мое состояние вытяжке XML

<selector xmlns:android="http://schemas.android.com/apk/res/android"> 

<item android:drawable="@drawable/add_schedule_button_checked_pressed" android:state_checked="true" android:state_pressed="true"/> 

<!-- <item android:drawable="@drawable/add_schedule_button_checked_focused" --> 
<!-- android:state_checked="true" --> 
<!-- android:state_focused="true" /> --> 

<item android:drawable="@drawable/selected_card_shape_w_shadow_white" android:state_checked="true"/> 

<!-- <item android:drawable="@drawable/add_schedule_button_unchecked_pressed" --> 
<!-- android:state_pressed="true" /> --> 


<!-- <item android:drawable="@drawable/add_schedule_button_unchecked_focused" --> 
<!-- android:state_focused="true" /> --> 

Мой макет

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:id="@+id/topics_preview_main_frame" 
android:layout_width="match_parent" 
android:layout_height="match_parent" > 

<LinearLayout 
    android:id="@+id/favorites_header_layout" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_marginLeft="6dp" 
    android:layout_marginRight="6dp" 
    android:layout_marginTop="2dp" 
    android:orientation="vertical" > 

    <TextView 
     android:id="@+id/favorites_header_title" 
     style="@style/CardText" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_marginBottom="4dp" 
     android:layout_marginLeft="6dp" 
     android:layout_marginRight="6dp" 
     android:layout_marginTop="4dp" 
     android:background="@drawable/card" 
     android:gravity="left" 
     android:paddingBottom="10dp" 
     android:paddingLeft="5dp" 
     android:paddingTop="10dp" 
     android:text="@string/favorites_header" /> 

    <ui.CheckableLinearLayout 
     android:id="@+id/favorites_layout" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_marginBottom="4dp" 
     android:layout_marginLeft="6dp" 
     android:layout_marginRight="6dp" 
     android:layout_marginTop="4dp" 
     android:background="@drawable/selector_card_shape_w_shadow_white" 
     android:clickable="true" 
     android:longClickable="true" 
     android:orientation="vertical" 
     android:paddingBottom="16dp" > 

     <LinearLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:gravity="center_vertical" 
      android:paddingLeft="8dp" 
      android:paddingRight="8dp" > 

      <TextView 
       android:id="@+id/favorites_title" 
       style="@style/CardTitle" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:text="title" /> 
     </LinearLayout> 

     <View 
      android:layout_width="match_parent" 
      android:layout_height="1dp" 
      android:layout_marginTop="4dp" 
      android:background="@color/C_Favorites_Pink" /> 

     <LinearLayout 
      android:id="@+id/favorites_description_layout" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:gravity="center_vertical" 
      android:orientation="vertical" 
      android:padding="4dp" > 

      <TextView 
       android:id="@+id/favorites_description" 
       style="@style/CardText" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:layout_marginLeft="8dp" 
       android:ellipsize="end" 
       android:maxLines="4" 
       android:text="Lorem ipsum dolor sit amet" /> 
     </LinearLayout> 
    </ui.CheckableLinearLayout> 
</LinearLayout> 

Мой фрагмент

private void onFavoriteClick(final MCourse courseInfo, 
     LinearLayout favoritesLayout) { 
    favoritesLayout.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      // TODO Auto-generated method stub 
      String courseId = Integer.toString(v.getId()); 
      String courseName = courseInfo.getFullname(); 

      Bundle bundle = new Bundle(); 
      bundle.putString("courseId", courseId); 
      bundle.putString("courseName", courseName); 

      FragmentManager fragmentManager = getFragmentManager(); 
      FragmentTransaction fragmentTransaction = fragmentManager 
        .beginTransaction(); 

      TopicsPreview insideTopicsFrag = new TopicsPreview(); 
      insideTopicsFrag.setArguments(bundle); 
      fragmentTransaction 
        .replace(R.id.mainFragment, insideTopicsFrag); 
      fragmentTransaction.commit(); 

     } 
    }); 
} 
+1

если кто-то хочет получить полное решение, проверить этот репозиторий: https://github.com/shamanland/AndroidLayoutSelector есть пользовательский clickable/checkable '' 'LinearLayout''', как' '' ToggleButton''' –

+0

И с этим lib проверенный drawable перекрывает полный размер макета !? проверьте проблему [здесь] (http://stackoverflow.com/questions/19099467/android-selector-draw-doesnt-overlap) – firetrap

ответ

3

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

в качестве альтернативы, вы можете использовать следующий раствор вместо:

вы можете позвонить setOnClickListener и setOnLongClickListener на CTOR, и есть логика в новых функций в соответствии с текущим состоянием, как таковой:

public CheckableLinearLayout(Context context, AttributeSet attrs) 
    { 
    super(context, attrs); 
    setOnClickListener(null); 
    } 

для того, чтобы «внешний мир» работать с этими новыми методами, вам нужно, чтобы сделать их как обертки, например:

public void setOnClickListener(... listener) 
    { 
    super.setOnClickListener(new ... 
    { 
    @Override 
    public void onClick(...) 
     { 
     // TODO add add logic that you wanted according to the state of the view 
     if(listener!=null) 
     listener.onClick(...); 
     } 
    }); 
    } 

подобной вещь должны быть реализованы для долгого щелчка.

btw, вы забыли добавить обработку пакета savedState. читайте here за недостающие вещи.

вот мой код, который я опробованный на работу с «проверяемостью» макет:

public class CheckableLinearLayout extends LinearLayout implements Checkable 
    { 
    private boolean    mChecked; 
    private static final String TAG    =CheckableLinearLayout.class.getCanonicalName(); 
    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked}; 

    public CheckableLinearLayout(final Context context) 
    { 
    super(context); 
    setClickable(true); 
    setLongClickable(true); 
    } 

    public CheckableLinearLayout(final Context context,final AttributeSet attrs) 
    { 
    super(context,attrs); 
    setClickable(true); 
    setLongClickable(true); 
    } 

    @TargetApi(Build.VERSION_CODES.HONEYCOMB) 
    public CheckableLinearLayout(final Context context,final AttributeSet attrs,final int defStyle) 
    { 
    super(context,attrs,defStyle); 
    setClickable(true); 
    setLongClickable(true); 
    } 

    @Override 
    public void setChecked(final boolean checked) 
    { 
    mChecked=checked; 
    refreshDrawableState(); 
    } 

    @Override 
    protected int[] onCreateDrawableState(final int extraSpace) 
    { 
    final int[] drawableState=super.onCreateDrawableState(extraSpace+1); 
    if(isChecked()) 
     mergeDrawableStates(drawableState,CHECKED_STATE_SET); 
    return drawableState; 
    } 

    @Override 
    protected void drawableStateChanged() 
    { 
    super.drawableStateChanged(); 
    final Drawable drawable=getBackground(); 
    if(drawable!=null) 
     { 
     final int[] myDrawableState=getDrawableState(); 
     drawable.setState(myDrawableState); 
     invalidate(); 
     } 
    } 

    @Override 
    public boolean performClick() 
    { 
    Toast.makeText(getContext(),"click",Toast.LENGTH_SHORT).show(); 
    return super.performClick(); 
    } 

    @Override 
    public boolean performLongClick() 
    { 
    Toast.makeText(getContext(),"long click",Toast.LENGTH_SHORT).show(); 
    return super.performLongClick(); 
    } 

    @Override 
    public boolean isChecked() 
    { 
    return mChecked; 
    } 

    @Override 
    public void toggle() 
    { 
    setChecked(!mChecked); 
    } 

    @Override 
    public Parcelable onSaveInstanceState() 
    { 
    // Force our ancestor class to save its state 
    final Parcelable superState=super.onSaveInstanceState(); 
    final SavedState savedState=new SavedState(superState); 
    savedState.checked=isChecked(); 
    return savedState; 
    } 

    @Override 
    public void onRestoreInstanceState(final Parcelable state) 
    { 
    final SavedState savedState=(SavedState)state; 
    super.onRestoreInstanceState(savedState.getSuperState()); 
    setChecked(savedState.checked); 
    requestLayout(); 
    } 

    // ///////////// 
    // SavedState // 
    // ///////////// 
    private static class SavedState extends BaseSavedState 
    { 
    boolean           checked; 
    @SuppressWarnings("unused") 
    public static final Parcelable.Creator<SavedState> CREATOR; 
    static 
     { 
     CREATOR=new Parcelable.Creator<SavedState>() 
     { 
      @Override 
      public SavedState createFromParcel(final Parcel in) 
      { 
      return new SavedState(in); 
      } 

      @Override 
      public SavedState[] newArray(final int size) 
      { 
      return new SavedState[size]; 
      } 
     }; 
     } 

    SavedState(final Parcelable superState) 
     { 
     super(superState); 
     } 

    private SavedState(final Parcel in) 
     { 
     super(in); 
     checked=(Boolean)in.readValue(null); 
     } 

    @Override 
    public void writeToParcel(final Parcel out,final int flags) 
     { 
     super.writeToParcel(out,flags); 
     out.writeValue(checked); 
     } 

    @Override 
    public String toString() 
     { 
     return TAG+".SavedState{"+Integer.toHexString(System.identityHashCode(this))+" checked="+checked+"}"; 
     } 
    } 
    } 
+0

Позвольте мне посмотреть, понимаю ли я, что вы говорите, я должен поставить прослушивание setOnClick в конструкторе этой точки зрения ?!Я реализую onclickListener в фрагменте, который раздувает этот макет. Не могли бы вы объяснить мне, что вы говорите. спасибо;) – firetrap

+0

я не понимаю. во всяком случае, я обновил свой ответ с полным кодом, который работает. обратите внимание, если вы хотите обрабатывать события касания, даже если макет имеет дочерние элементы, которые можно щелкнуть, вам нужно переопределить onInterceptTouchEvent и вернуть туда true. –

+0

Спасибо @android, что вы спасете мой день :) Вы тот человек, который еще раз знает спасибо – firetrap