nirhart / ParallaxScroll

Parallax ScrollView and ListView for Android
MIT License
848 stars 187 forks source link

Dividers #7

Open mypplication opened 10 years ago

mypplication commented 10 years ago

Hello, I have a problem with ParallaxListView when i use it with a single header. In my header, i have a dark background. I have also dividers enabled in my listview. When i scroll, i see the header's background hover the dividers..

do you know this problem ? (tested on Kitkat/ICS/gingerbread)

thank you

nirhart commented 10 years ago

I guess its make sense since the dividers are draw separately from the views - that get offset to make the parallax effect. I think that the best thing will be to override the way the dividers work in the ParrallaxListView but for now you can use your dividers as part of your views and it will work fine - you can make a vertical linear layout that contains your list view item with addition of a separator view.

mypplication commented 10 years ago

Yes, that's exactly what I did. I just was pointing the problem for your knowledge :)

erickhun commented 10 years ago

Hi @mypplication , Could you provide an example of the fix? I'd like to remove the dividers showing the background

edit: adding android:divider="@null" to the ParallaxListView fixed it

        <com.nirhart.parallaxscroll.views.ParallaxListView xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/list_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:parallax_factor="1.9"
            tools:context=".MainActivity"
            android:divider="@null"
        />
imoblife commented 10 years ago

No it did't work. Whenever parallax background is drawing with the list, they just mix up.

mypplication commented 10 years ago

If you want definitively remove divider in your listview, set android:divider="@null" and android:dividerHeight="0dp"

imoblife commented 10 years ago

thank you

LukeDeighton commented 9 years ago

@nirhart I've found a pretty horrendous solution since it requires API 18, but at least it might be helpful for yourself to figure out a better way. So the problem is with the headerview drawing over the divider/adapter views. Ideally the headerview can be clipped by the offset so that it doesn't draw over the adapter views (this happens if you add any transparency to the adapter views, you can see an odd effect with the parallax). API 18 added a way to clip views but only clips itself and not its children.

I tried a quick solution below just to prove it could work:

view.setTranslationY(offset);
if (android.os.Build.VERSION.SDK_INT >= 18) { //obv this could be optimised
    Rect clipRect = new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom() + (int) offset);
    view.setClipBounds(clipRect);
    if(view instanceof ViewGroup) { //here we would have to act recursively to get all children views and set the clipping on every child and child's child (ughh)
        ((ViewGroup) view).getChildAt(0).setClipBounds(clipRect);
    }
}

The actual code to clip the view isn't big (when thinking of compatibility). see: http://stackoverflow.com/questions/18724976/can-setclipbounds-be-called-on-a-view-before-it-has-been-drawn#answer-19927060

But it would be very inconvenient if every view within the headerview had to extend a custom view

LukeDeighton commented 9 years ago

@nirhart I had another attempt tonight to find an easier solution and here it is.

public class ClippingRelativeLayout extends RelativeLayout {

    private int offset;

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

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.clipRect(new Rect(getLeft(), getTop(), getRight(), getBottom() + offset));
        super.dispatchDraw(canvas);
    }

    public void setClipY(int offset) {
        this.offset = offset;
        invalidate();
    }
}

by doing the clipRect() in dispatchDraw all the children are clipped and therefore don't need the recursive approach above. It is also fully compatible (although I haven't tested on older versions of android). Then in ParallaxView:

@SuppressLint("NewApi")
    public void setOffset(float offset) {
        ClippingRelativeLayout view = this.view.get();
        if (view != null) {
            if (isAPI11) {
                view.setTranslationY(offset);
            } else {
                translatePreICS(view, offset);
            }
            view.setClipY((int) offset);
        }
}

And then

public void addParallaxedHeaderView(View v) {
        ClippingRelativeLayout clippingLayout = new ClippingRelativeLayout(v.getContext());
        clippingLayout.addView(v);

        super.addHeaderView(clippingLayout);
        helper.addParallaxedHeaderView(clippingLayout);
    }

Note - It would need testing/tweaking for adding multiple HeaderViews.

Edit: It also needs sorting for parallax factors other than 1.9

nirhart commented 9 years ago

@LukeDeighton Thank you very much for your contribution, I'll take a look at it once I'll have some spare time

a-marwane commented 9 years ago

@nirhart Any update regarding the issue? Thanks.

mawenge commented 8 years ago

@LukeDeighton awesome!