2017-07-11 31 views
10

Tôi đã tạo một lần xem hình tùy chỉnh. Nó hoạt động tốt nếu bạn sử dụng nó trong scrollview. Nhưng khi tôi cố gắng sử dụng nó trong một recyclerview có một hành vi kỳ lạ tôi quan sát thấy. Hình ảnh không được vẽ và hiển thị khoảng cách (xem hình ảnh thứ nhất) trừ khi bạn cuộn xuống (xem hình ảnh thứ 2). Điều tương tự cũng xảy ra khi bạn cuộn lên.RecyclerView với các mục có hình dạng tùy chỉnh

Tôi muốn biết cách tránh những khoảng trống này. Bạn có thể vui lòng chỉ cho tôi nơi tôi đang làm sai? Cảm ơn đã giúp đỡ.

trạng thái ban đầu hoặc sau khi di chuyển lên:

Initial state

Sau khi di chuyển xuống:

After scrolling down

import android.content.Context; 
import android.content.res.TypedArray; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.Paint.Style; 
import android.graphics.Path; 
import android.support.v7.widget.AppCompatImageView; 
import android.util.AttributeSet; 

/** 
* Created by santalu on 7/4/17. 
*/ 

public class DiagonalImageView extends AppCompatImageView { 

    public static final int TOP = 0; 
    public static final int MIDDLE = 1; 
    public static final int BOTTOM = 2; 

    private final Path mClipPath = new Path(); 
    private final Path mLinePath = new Path(); 

    private final Paint mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); 

    private int mPosition; 
    private int mOverlap; 
    private int mLineColor; 
    private int mLineSize; 

    private boolean mMaskEnabled = true; 

    public DiagonalImageView(Context context) { 
     super(context); 
     init(context, null); 
    } 

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

    private void init(Context context, AttributeSet attrs) { 
     if (attrs == null) { 
      return; 
     } 

     TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ShowCaseImageView); 
     try { 
      mPosition = a.getInt(R.styleable.DiagonalImageView_di_position, TOP); 
      mOverlap = a.getDimensionPixelSize(R.styleable.DiagonalImageView_di_overlap, 0); 
      mLineSize = a.getDimensionPixelSize(R.styleable.DiagonalImageView_di_lineSize, 0); 
      mLineColor = a.getColor(R.styleable.DiagonalImageView_di_lineColor, Color.BLACK); 

      mLinePaint.setColor(mLineColor); 
      mLinePaint.setStyle(Style.STROKE); 
      mLinePaint.setStrokeWidth(mLineSize); 
     } finally { 
      a.recycle(); 
     } 
    } 

    public void setPosition(int position, boolean maskEnabled) { 
     mMaskEnabled = maskEnabled; 
     setPosition(position); 
    } 

    public void setPosition(int position) { 
     if (mPosition != position) { 
      mClipPath.reset(); 
      mLinePath.reset(); 
     } 
     mPosition = position; 
    } 

    @Override protected void onDraw(Canvas canvas) { 
     int saveCount = canvas.getSaveCount(); 
     canvas.clipPath(mClipPath); 
     super.onDraw(canvas); 
     canvas.drawPath(mLinePath, mLinePaint); 
     canvas.restoreToCount(saveCount); 
    } 

    @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 
     super.onLayout(changed, left, top, right, bottom); 
     if (!changed) { 
      return; 
     } 

     if (mMaskEnabled && mClipPath.isEmpty()) { 
      int width = getMeasuredWidth(); 
      int height = getMeasuredHeight(); 

      if (width <= 0 || height <= 0) { 
       return; 
      } 

      switch (mPosition) { 
       case TOP: 
        mClipPath.moveTo(0, 0); 
        mClipPath.lineTo(width, 0); 
        mClipPath.lineTo(width, height - mOverlap); 
        mClipPath.lineTo(0, height); 

        mLinePath.moveTo(0, height); 
        mLinePath.lineTo(width, height - mOverlap); 
        break; 
       case MIDDLE: 
        mClipPath.moveTo(0, mOverlap); 
        mClipPath.lineTo(width, 0); 
        mClipPath.lineTo(width, height - mOverlap); 
        mClipPath.lineTo(0, height); 

        mLinePath.moveTo(0, height); 
        mLinePath.lineTo(width, height - mOverlap); 
        break; 
       case BOTTOM: 
        mClipPath.moveTo(0, mOverlap); 
        mClipPath.lineTo(width, 0); 
        mClipPath.lineTo(width, height); 
        mClipPath.lineTo(0, height); 
        break; 
      } 
      mClipPath.close(); 
      mLinePath.close(); 
     } 
    } 
} 

tôi bao gồm các ứng dụng mẫu ở đây để chứng minh vấn đề này nếu bạn quan tâm

import android.content.Context; 
import android.graphics.Rect; 
import android.os.Bundle; 
import android.support.v7.app.AppCompatActivity; 
import android.support.v7.widget.LinearLayoutManager; 
import android.support.v7.widget.RecyclerView; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 

import com.santalu.showcaseimageview.ShowCaseImageView; 

public class MainActivity extends AppCompatActivity { 

    @Override protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     int overlap = getResources().getDimensionPixelSize(R.dimen.overlap_size); 
     RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); 
     LinearLayoutManager layoutManager = new LinearLayoutManager(this); 
     recyclerView.setLayoutManager(layoutManager); 
     recyclerView.setHasFixedSize(true); 
     recyclerView.addItemDecoration(new OverlapItemDecoration(-overlap)); 
     recyclerView.setAdapter(new SampleAdapter(this)); 
    } 

    static class SampleAdapter extends RecyclerView.Adapter<SampleAdapter.ViewHolder> { 
     private final Context mContext; 

     SampleAdapter(Context context) { 
      mContext = context; 
     } 

     @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
      return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item, parent, false)); 
     } 

     @Override public void onBindViewHolder(ViewHolder holder, int position) { 
      holder.bind(position); 
     } 

     @Override public int getItemCount() { 
      return 7; 
     } 

     class ViewHolder extends RecyclerView.ViewHolder { 
      DiagonalImageView image; 
      //int overlap; 

      ViewHolder(View itemView) { 
       super(itemView); 
       image = (DiagonalImageView) itemView.findViewById(R.id.image); 
       //overlap = -mContext.getResources().getDimensionPixelSize(R.dimen.overlap_size); 
      } 

      void bind(int position) { 
       boolean maskEnabled = getItemCount() > 1; 
       //MarginLayoutParams params = (MarginLayoutParams) image.getLayoutParams(); 
       if (position == 0) { 
        image.setPosition(ShowCaseImageView.TOP, maskEnabled); 
        //params.setMargins(0, 0, 0, 0); 
       } else if (position == getItemCount() - 1) { 
        image.setPosition(ShowCaseImageView.BOTTOM, maskEnabled); 
        //params.setMargins(0, overlap, 0, 0); 
       } else { 
        image.setPosition(ShowCaseImageView.MIDDLE, maskEnabled); 
        //params.setMargins(0, overlap, 0, 0); 
       } 
       //image.setLayoutParams(params); 
      } 
     } 
    } 

    static class OverlapItemDecoration extends RecyclerView.ItemDecoration { 
     private int mOverlap; 

     OverlapItemDecoration(int overlap) { 
      mOverlap = overlap; 
     } 

     @Override 
     public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 
      super.getItemOffsets(outRect, view, parent, state); 
      if (parent.getChildAdapterPosition(view) != 0) { 
       outRect.top = mOverlap; 
      } 
     } 
    } 
} 

item.xml

<?xml version="1.0" encoding="utf-8"?> 
<com.santalu.diagonalimageview.DiagonalImageView 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:id="@+id/image" 
    android:layout_width="wrap_content" 
    android:layout_height="@dimen/image_height" 
    android:scaleType="centerCrop" 
    android:src="@drawable/demo" 
    app:csi_lineColor="@color/deep_orange" 
    app:csi_lineSize="@dimen/line_size" 
    app:csi_overlap="@dimen/overlap_size"/> 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?> 
<android.support.v7.widget.RecyclerView 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/recycler_view" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"/> 

Trả lời

8

Sau khi một số resea rch và thử tôi đã tìm ra rằng Đường dẫn giá trị không chính xác và được thiết kế đặc biệt cho đường viền. Một số trường hợp chúng chồng lên nhau và tôi nghĩ điều này khiến ảnh không được vẽ chính xác.

Tôi đã thiết kế lại chế độ xem và thực hiện một số cải tiến. Đối với độc giả trong tương lai đây là mã cuối cùng:

/** 
* Created by santalu on 7/4/17. 
* 
* Note: if position set NONE mask won't be applied 
* 
* POSITION DIRECTION 
* 
* TOP   LEFT | RIGHT 
* BOTTOM  LEFT | RIGHT 
* LEFT  TOP | BOTTOM 
* RIGHT  TOP | BOTTOM 
*/ 

public class DiagonalImageView extends AppCompatImageView { 

    private static final String TAG = DiagonalImageView.class.getSimpleName(); 

    public static final int NONE = 0; 
    public static final int TOP = 1; 
    public static final int RIGHT = 2; 
    public static final int BOTTOM = 4; 
    public static final int LEFT = 8; 

    private final Path mClipPath = new Path(); 
    private final Path mBorderPath = new Path(); 

    private final Paint mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 

    private int mPosition; 
    private int mDirection; 
    private int mOverlap; 
    private int mBorderColor; 
    private int mBorderSize; 

    private boolean mBorderEnabled; 

    public DiagonalImageView(Context context) { 
     super(context); 
     init(context, null); 
    } 

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

    private void init(Context context, AttributeSet attrs) { 
     if (attrs == null) { 
      return; 
     } 

     TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DiagonalImageView); 
     try { 
      mPosition = a.getInteger(R.styleable.DiagonalImageView_di_position, NONE); 
      mDirection = a.getInteger(R.styleable.DiagonalImageView_di_direction, RIGHT); 
      mOverlap = a.getDimensionPixelSize(R.styleable.DiagonalImageView_di_overlap, 0); 
      mBorderSize = a.getDimensionPixelSize(R.styleable.DiagonalImageView_di_borderSize, 0); 
      mBorderColor = a.getColor(R.styleable.DiagonalImageView_di_borderColor, Color.BLACK); 
      mBorderEnabled = a.getBoolean(R.styleable.DiagonalImageView_di_borderEnabled, false); 

      mBorderPaint.setColor(mBorderColor); 
      mBorderPaint.setStyle(Style.STROKE); 
      mBorderPaint.setStrokeWidth(mBorderSize); 
     } finally { 
      a.recycle(); 
     } 
    } 

    public void set(int position, int direction) { 
     if (mPosition != position || mDirection != direction) { 
      mClipPath.reset(); 
      mBorderPath.reset(); 
     } 
     mPosition = position; 
     mDirection = direction; 
     postInvalidate(); 
    } 

    public void setPosition(int position) { 
     if (mPosition != position) { 
      mClipPath.reset(); 
      mBorderPath.reset(); 
     } 
     mPosition = position; 
     postInvalidate(); 
    } 

    public void setDirection(int direction) { 
     if (mDirection != direction) { 
      mClipPath.reset(); 
      mBorderPath.reset(); 
     } 
     mDirection = direction; 
     postInvalidate(); 
    } 

    public void setBorderEnabled(boolean enabled) { 
     mBorderEnabled = enabled; 
     postInvalidate(); 
    } 

    @Override protected void onDraw(Canvas canvas) { 
     if (mClipPath.isEmpty()) { 
      super.onDraw(canvas); 
      return; 
     } 

     int saveCount = canvas.save(); 
     canvas.clipPath(mClipPath); 
     super.onDraw(canvas); 
     if (!mBorderPath.isEmpty()) { 
      canvas.drawPath(mBorderPath, mBorderPaint); 
     } 
     canvas.restoreToCount(saveCount); 
    } 

    @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 
     super.onLayout(changed, left, top, right, bottom); 
     if (!changed) { 
      return; 
     } 

     if (mClipPath.isEmpty()) { 
      int width = getMeasuredWidth(); 
      int height = getMeasuredHeight(); 

      if (width <= 0 || height <= 0) { 
       return; 
      } 

      mClipPath.reset(); 
      mBorderPath.reset(); 

      switch (mPosition) { 
       case TOP: 
        if (mDirection == LEFT) { 
         mClipPath.moveTo(0, 0); 
         mClipPath.lineTo(width, mOverlap); 
         mClipPath.lineTo(width, height); 
         mClipPath.lineTo(0, height); 

         if (mBorderEnabled) { 
          mBorderPath.moveTo(0, 0); 
          mBorderPath.lineTo(width, mOverlap); 
         } 
        } else { 
         mClipPath.moveTo(0, mOverlap); 
         mClipPath.lineTo(width, 0); 
         mClipPath.lineTo(width, height); 
         mClipPath.lineTo(0, height); 

         if (mBorderEnabled) { 
          mBorderPath.moveTo(0, mOverlap); 
          mBorderPath.lineTo(width, 0); 
         } 
        } 
        break; 
       case RIGHT: 
        if (mDirection == TOP) { 
         mClipPath.moveTo(0, 0); 
         mClipPath.lineTo(width, 0); 
         mClipPath.lineTo(width - mOverlap, height); 
         mClipPath.lineTo(0, height); 

         if (mBorderEnabled) { 
          mBorderPath.moveTo(width, 0); 
          mBorderPath.lineTo(width - mOverlap, height); 
         } 
        } else { 
         mClipPath.moveTo(0, 0); 
         mClipPath.lineTo(width - mOverlap, 0); 
         mClipPath.lineTo(width, height); 
         mClipPath.lineTo(0, height); 

         if (mBorderEnabled) { 
          mBorderPath.moveTo(width - mOverlap, 0); 
          mBorderPath.lineTo(width, height); 
         } 
        } 
        break; 
       case BOTTOM: 
        if (mDirection == LEFT) { 
         mClipPath.moveTo(0, 0); 
         mClipPath.lineTo(width, 0); 
         mClipPath.lineTo(width, height - mOverlap); 
         mClipPath.lineTo(0, height); 

         if (mBorderEnabled) { 
          mBorderPath.moveTo(0, height); 
          mBorderPath.lineTo(width, height - mOverlap); 
         } 
        } else { 
         mClipPath.moveTo(0, 0); 
         mClipPath.lineTo(width, 0); 
         mClipPath.lineTo(width, height); 
         mClipPath.lineTo(0, height - mOverlap); 

         if (mBorderEnabled) { 
          mBorderPath.moveTo(0, height - mOverlap); 
          mBorderPath.lineTo(width, height); 
         } 
        } 
        break; 
       case LEFT: 
        if (mDirection == TOP) { 
         mClipPath.moveTo(0, 0); 
         mClipPath.lineTo(width, 0); 
         mClipPath.lineTo(width, height); 
         mClipPath.lineTo(mOverlap, height); 

         if (mBorderEnabled) { 
          mBorderPath.moveTo(0, 0); 
          mBorderPath.lineTo(mOverlap, height); 
         } 
        } else { 
         mClipPath.moveTo(mOverlap, 0); 
         mClipPath.lineTo(width, 0); 
         mClipPath.lineTo(width, height); 
         mClipPath.lineTo(0, height); 

         if (mBorderEnabled) { 
          mBorderPath.moveTo(mOverlap, 0); 
          mBorderPath.lineTo(0, height); 
         } 
        } 
        break; 
      } 

      mClipPath.close(); 
      mBorderPath.close(); 
     } 
    } 
} 

Cập nhật: tôi công bố này trên Github như một thư viện trong trường hợp bạn cần nó Diagonal ImageView

1

bạn nên sử dụng bố trí cắt cho hàng mục XML ở đây là liên kết https://github.com/florent37/DiagonalLayout

<com.github.florent37.diagonallayout.DiagonalLayout 
    android:layout_width="match_parent" 
    android:layout_height="250dp" 
    android:elevation="10dp" 
    app:diagonal_angle="20" 
    app:diagonal_position="top" 
    app:diagonal_direction="right"> 

    <ImageView 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:scaleType="centerCrop" 
     android:src="@drawable/mountains" /> 

+1

Cảm ơn đã nhận xét. Tôi biết thư viện này. Nhưng như bạn có thể thấy từ ảnh chụp màn hình tôi cung cấp các mục recyclerview chồng chéo nhau và tất cả các mục có chia riêng của họ (đường màu cam). Và đường dẫn clip của tưởng tượng và đường phân chia được tính bằng chiều cao chồng chéo không phải là góc để đảm bảo mỗi mục đều tôn trọng các liên kết của chúng và được vẽ chính xác. Tôi chỉ muốn biết có gì sai với chế độ xem của tôi hoặc triển khai recyclerview. Nhưng cảm ơn cho đề xuất – santalu

+0

Bên cạnh đó cùng một vấn đề xảy ra với thư viện này quá. Hãy thử sử dụng nó trong recyclerview. – santalu

+0

bạn đã đặt vị trí đường chéo, trong XML phải giống như đường chéo này: diagonal_position = "bottom". Tôi không chắc chắn, nhưng nếu bạn kiểm tra chỉ số cuối cùng hơn bạn có thể sử dụng bố trí khác nhau cho nó, nơi trong đó vị trí chéo được thiết lập để dưới cùng. – farhana

Các vấn đề liên quan