Stretchy Header ListView

TomasWinstonTomasWinston IEMember ✭✭
edited April 2016 in Xamarin.Forms

Hi,

I have been trying to implement a Stretchy Header listview in Xamarin Forms as described here by "Mike Codes" for Xamarin.iOS here. I saw that @JamesMontemagno implemented something like it for the Xamarin Evolve 2016 app here. In that, from what I can see James isn't using a ListView but rather using a scrollview with a separate Grid as a header for the whole page.

I may be taking a completely wrong approach here (given that it is not working for me!) but I have added a "Header" to my listview - the content of which is an image with AspectFill. I implemented a custom renderer for a listview (call it StretchyHeaderListView) and using a custom TableViewSource in which I capture the Scrolled event and call James' Parralax() procedure passing in the ContentOffser.Y of the scrollview (from tableviewsource).

Anyway, long story short - its not working the way I hoped. The image initially seems to start scaling but then just disappears up above the parent view/page.

Here is the code I have:

Page.Xaml

    <customcontrols:StretchyHeaderListView x:Name="list" SeparatorColor="#999999" Grid.Row="0" RowHeight="120" ItemsSource="{Binding MembersNames}">
        <ListView.Header>
            <Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" x:Name="headerView">
                <Image Grid.Row="0" Grid.Column="0" HeightRequest="200" Source="HeaderImage.png" Aspect="AspectFill" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
            </Grid>
        </ListView.Header>
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell x:Name="viewCell">
                    <Label Text="{Binding MemberName}" />
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
        <ListView.Footer>
            <Grid HeightRequest="50">
            </Grid>
        </ListView.Footer>
    </customcontrols:StretchyHeaderListView>

Page.Xaml.cs

    public Page()
    {
        InitializeComponent();
        list.ParallaxView = headerView;
    }

StretchyHeaderListView.cs (PCL Project) - Using Parralax procedure from Xamarin Evolve 2016 app here.

   public class StretchyHeaderListView : MR.Gestures.ListView
    {
        public StretchyHeaderListView ()
        {

        }
        public static readonly BindableProperty ParallaxViewProperty =
              BindableProperty.Create(nameof(ParallaxView), typeof(View), typeof(StretchyHeaderListView), null);


        public View ParallaxView
        {
            get { return (View)GetValue(ParallaxViewProperty); }
            set { SetValue(ParallaxViewProperty, value); }
        }

        double height;
        public void Parallax(float scrollY)
        {
            if (ParallaxView == null || Device.OS == TargetPlatform.Windows || Device.OS == TargetPlatform.WinPhone)
                return;

            if (height <= 0)
                height = ParallaxView.Height;
            var y = -(int)((float)scrollY / 2.5f);
            if (y < 0)
            {
                //Move the Image's Y coordinate a fraction of the ScrollView's Y position
                ParallaxView.Scale = 1;
                ParallaxView.TranslationY = y;
            }
            else if (Device.OS == TargetPlatform.iOS)
            {
                Debug.WriteLine(scrollY.ToString());
                //Calculate a scale that equalizes the height vs scroll
                double newHeight = height + (scrollY * -1);
                ParallaxView.Scale = newHeight / height;
                ParallaxView.TranslationY = -(scrollY / 2);

            }
            else
            {
                ParallaxView.Scale = 1;
                ParallaxView.TranslationY = 0;
            }
        }
    }

iOS Custom Renderer for ListView

    [assembly: ExportRenderer(typeof(StretchyHeaderListView), typeof(StretchyHeaderListViewRenderer))]
    namespace MyApp
    {
        public class StretchyHeaderListViewRenderer : ListViewRenderer
        {
            UITableView _table=null;
            public StretchyHeaderListViewRenderer ()
            {
            }


            protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.ListView> e)
            {
                base.OnElementChanged (e);

                if (e.NewElement != null) {
                    _table = (UITableView)this.Control;

                    Control.Source = new StretchyHeaderListViewTableSource(e.NewElement as StretchyHeaderListView, _table);
                }
            }
        }
    }

StretchyHeaderListViewTableSource.cs (custom UITableViewSource to handle the scrolled event and call Parallax() in listview)

public class StretchyHeaderListViewTableSource : UITableViewSource
{


    IEnumerable<Object> items;
    private StretchyHeaderListView listView;
    readonly NSString cellIdentifier = new NSString("TableCell");
    UITableView _tableView;
    public StretchyHeaderListViewTableSource(StretchyHeaderListView view, UITableView tableView)
    {
        listView = view;
        items = view.ItemsSource as IEnumerable<Object>;
        _tableView = tableView;
    }

    public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
    {
        UITableViewCell cell = tableView.DequeueReusableCell(cellIdentifier) as UITableViewCell;

        if (cell == null)
        {
            cell = new UITableViewCell(UITableViewCellStyle.Default,cellIdentifier);
        }

        return cell;

    }

    public override nint RowsInSection(UITableView tableview, nint section)
    {
        return (items == null) ? 0 : items.Count();
    }

    public override void Scrolled(UIScrollView scrollView)
    {
        listView.Parallax((float)scrollView.ContentOffset.Y);
    }
}

So there you have it. I have tried and failed - I know its a long post but if someone can shed some light on what I MIGHT be doing wrong that would be fantastic.

Thank you.

Tomás

Tagged:

Answers

  • SpaceMonkeySpaceMonkey GBMember ✭✭✭

    . I saw that @JamesMontemagno implemented something like it for the Xamarin Evolve 2016 app here.

    Where is that !?? I have the app running and I don't see that anywhere

  • TomasWinstonTomasWinston IEMember ✭✭
    edited May 2016

    Its on the Speaker Profile page. For example. Pick a session, then scroll down to the speaker and click on them to bring you to their profile page. But as I said this is the kind of effect I want except using a ListView with Header - instead of James' use of a scrollview and separate grid...

  • SpaceMonkeySpaceMonkey GBMember ✭✭✭

    @TomasWinston

    Nope, it doesn't have that effect, it's just a normal scrolling page. I have no idea why you think that's the same as what's shown in the page you linked

  • SpaceMonkeySpaceMonkey GBMember ✭✭✭

    ah I see now, I thought you're using Android. My bad.

Sign In or Register to comment.