【问题标题】:How to set foreground attribute to other non FrameLayout view如何将前景属性设置为其他非 FrameLayout 视图
【发布时间】:2013-05-23 04:04:32
【问题描述】:

我想知道如何在不同于 FrameLayout 的视图中应用或模拟前景效果,如 LinearLayout 或 RelativeLayout

这就是我现在拥有的:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cardContent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/row_background"
    android:foreground="@drawable/foreground_row">

    ...

</FrameLayout>

我想要类似的东西:

<?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/cardContent"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/row_background"
        app:foreground="@drawable/foreground_row">

        ...

    </RelativeLayout>

提前致谢!!

【问题讨论】:

    标签: android view drawable android-view android-framelayout


    【解决方案1】:

    这个想法是用 FrameLayout 围绕您的布局,并将选择器和 onClick 事件设置为该布局。

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:id="@+id/selectableItem"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:foreground="@drawable/foreground_row"
        >
    
       <RelativeLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/cardContent"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/row_background">
    
            ...
    
        </RelativeLayout>
    </FrameLayout>
    

    你可以在我的博客上找到完整的解释:

    http://antonioleiva.com/unveiling-bandhook-foreground-any-layout/

    或者你可以扩展 rhis FRelativeLayout https://gist.github.com/shakalaca/6199283

    【讨论】:

    • 如果您只想使用foreground 属性ImageView 上添加波纹,则有一个simpler and better solution,而不是将其包装在&lt;FrameLayout&gt; 中或继承它。
    【解决方案2】:

    Checkout ForegroundView 与 Gradle 集成的库。它支持以下视图

    • ForegroundImageView
    • 前景按钮
    • ForegroundTextView
    • ForegroundImageButton
    • ForegroundEditText
    • ForegroundWebView
    • ForegroundLinearLayout
    • ForegroundRelativeLayout
    • ForegroundGridLayout
    • ForegroundGridView
    • ForegroundHorizo​​ntalScrollView
    • ForegroundListView
    • ForegroundScrollViewForegroundImageView

    【讨论】:

      【解决方案3】:

      这是一个可能的实现,它还支持检查布局。

      几乎相同的解决方案可以应用于您希望的任何布局视图(只有 CTOR 不同)。

      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 };
          private Drawable mForeground;
      
          public CheckableLinearLayout(final Context context) {
              this(context, null, 0);
          }
      
          public CheckableLinearLayout(final Context context, final AttributeSet attrs) {
              this(context, attrs, 0);
          }
      
          public CheckableLinearLayout(final Context context, final AttributeSet attrs, final int defStyle) {
              super(context, attrs, defStyle);
              final TypedArray a = context
                      .obtainStyledAttributes(attrs, R.styleable.CheckableLinearLayout, defStyle, 0);
              setForegroundEx(a.getDrawable(R.styleable.CheckableLinearLayout_foreground));
              a.recycle();
          }
      
          public void setForegroundEx(final Drawable drawable) {
              this.mForeground = drawable;
          }
      
          @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();
              boolean needRedraw = false;
              final int[] myDrawableState = getDrawableState();
              if (drawable != null) {
                  drawable.setState(myDrawableState);
                  needRedraw = true;
              }
              if (mForeground != null) {
                  mForeground.setState(myDrawableState);
                  needRedraw = true;
              }
              if (needRedraw)
                  invalidate();
          }
      
          @Override
          protected void onSizeChanged(final int width, final int height, final int oldwidth, final int oldheight) {
              super.onSizeChanged(width, height, oldwidth, oldheight);
              if (mForeground != null)
                  mForeground.setBounds(0, 0, width, height);
          }
      
          @Override
          protected void dispatchDraw(final Canvas canvas) {
              super.dispatchDraw(canvas);
              if (mForeground != null)
                  mForeground.draw(canvas);
          }
      
          @Override
          public boolean isChecked() {
              return mChecked;
          }
      
          @Override
          public void setChecked(final boolean checked) {
              mChecked = checked;
              refreshDrawableState();
              //TODO think if you wish to also check inner views, maybe even recursively
          }
      
          @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();
          }
      
          @SuppressLint("ClickableViewAccessibility")
          @TargetApi(Build.VERSION_CODES.LOLLIPOP)
          @Override
          public boolean onTouchEvent(final MotionEvent e) {
              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && //
                      e.getActionMasked() == MotionEvent.ACTION_DOWN && //
                      mForeground != null)
                  mForeground.setHotspot(e.getX(), e.getY());
              return super.onTouchEvent(e);
          }
      
          // /////////////
          // SavedState //
          // /////////////
      
          private static class SavedState extends BaseSavedState {
              boolean checked;
      
              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
                          + "}";
              }
      
              @SuppressWarnings("unused")
              public static final Parcelable.Creator<SavedState> 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];
                  }
              };
          }
      
      }
      

      attr.xml

      <declare-styleable name="CheckableLinearLayout">
          <attr name="foreground"/>
      </declare-styleable>
      

      这是一种更简单的方法,使用 Kotlin,并且没有可检查的部分:

      class LinearLayoutEx @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : LinearLayout(context, attrs, defStyle) {
          var foregroundDrawable: Drawable? = null
              set(value) {
                  field = value
                  invalidate()
              }
      
          init {
              val a = context
                      .obtainStyledAttributes(attrs, R.styleable.LinearLayoutEx, defStyle, 0)
              foregroundDrawable = a.getDrawable(R.styleable.LinearLayoutEx_foreground)
              a.recycle()
          }
      
          override fun drawableStateChanged() {
              super.drawableStateChanged()
              val drawable = background
              var needRedraw = false
              val myDrawableState = drawableState
              if (drawable != null) {
                  drawable.state = myDrawableState
                  needRedraw = true
              }
              if (foregroundDrawable != null) {
                  foregroundDrawable!!.state = myDrawableState
                  needRedraw = true
              }
              if (needRedraw)
                  invalidate()
          }
      
          override fun onSizeChanged(width: Int, height: Int, oldwidth: Int, oldheight: Int) {
              super.onSizeChanged(width, height, oldwidth, oldheight)
              foregroundDrawable?.setBounds(0, 0, width, height)
          }
      
          override fun dispatchDraw(canvas: Canvas) {
              super.dispatchDraw(canvas)
              foregroundDrawable?.draw(canvas)
          }
      
          @SuppressLint("ClickableViewAccessibility")
          @TargetApi(Build.VERSION_CODES.LOLLIPOP)
          override fun onTouchEvent(e: MotionEvent): Boolean {
              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && e.actionMasked == MotionEvent.ACTION_DOWN)
                  foregroundDrawable?.setHotspot(e.x, e.y)
              return super.onTouchEvent(e)
          }
      
      }
      

      attr.xml

      <declare-styleable name="LinearLayoutEx" tools:ignore="MissingDefaultResource">
          <attr name="foreground"/>
      </declare-styleable>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多