none
如何对瀑布流排版进行UI虚拟化... RRS feed

  • 问题

  • 在我的应用中由于需要浏览不同大小的图片,最后采用了类似于下图的瀑布流排版...

    但是由于图片比较多...必须进行UI虚拟化...优化内存使用...

    在虚拟化上遇到了问题...自己写的虚拟化比较繁琐...遍历子控件...导致翻页的时候比较卡顿...体验不好...

    不知道有什么比较好的虚拟化方案...或者是使用已有的系统自带虚拟化控件实现瀑布流排版...

    VirtualizingStackPanel的话...貌似不能多列...

    2014年12月23日 13:26

全部回复

  • 你好,

    请问你的这个布局是用什么方式实现的,可否贴出一部分关键的XAML代码?

    >>...自己写的虚拟化比较繁琐...遍历子控件

    你是如何去遍历然后虚拟的呢?


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    2014年12月24日 2:44
    版主
  •         <ScrollViewer x:Name="scrollViewer" ScrollViewer.ManipulationMode="Control">
                <toolkit:GestureService.GestureListener>
                    <toolkit:GestureListener DragStarted="GestureListener_DragStarted" DragDelta="GestureListener_DragDelta" DragCompleted="GestureListener_DragCompleted"></toolkit:GestureListener>
                </toolkit:GestureService.GestureListener>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="158*"/>
                        <ColumnDefinition Width="3*"/>
                        <ColumnDefinition Width="158*"/>
                    </Grid.ColumnDefinitions>
                    <ListBox Template="{StaticResource ListBoxTem}" x:Name="panel1" Grid.Column="0" VerticalAlignment="Top">
                    </ListBox>
                    <ListBox Template="{StaticResource ListBoxTem}" x:Name="panel2" Grid.Column="2"  Grid.ColumnSpan="2" VerticalAlignment="Top">
                    </ListBox>
                </Grid>
            </ScrollViewer>

    布局也是用的很繁琐的方式...左右两边都是一个ListBox...其实可以改成ItemsControl...一样的...这个时候ListBox的虚拟化已经被破坏...

    至于虚拟化...

    async Task v()
            {
                foreach (var key in dic1.Keys)
                {
                    if (key + dic1[key].PostItemInfo.Height < ScrollOffset || key > ScrollOffset + scrollViewer.ViewportHeight)
                    {
                        if (dic1[key].IsShowed)
                        {
                            Deployment.Current.Dispatcher.BeginInvoke(() =>
                            {
                                dic1[key].Hiden();
                            });
                        }
                    }
                    else
                    {
                        if (!dic1[key].IsShowed)
                        {
                            Deployment.Current.Dispatcher.BeginInvoke(() =>
                            {
                                dic1[key].Shown();
                            });
                        }
                    }
                }
    
                foreach (var key in dic2.Keys)
                {
                    if (key + dic2[key].PostItemInfo.Height < ScrollOffset || key > ScrollOffset + scrollViewer.ViewportHeight)
                    {
                        if (dic2[key].IsShowed)
                        {
                            Deployment.Current.Dispatcher.BeginInvoke(() =>
                            {
                                dic2[key].Hiden();
                            });
                        }
                    }
                    else
                    {
                        if (!dic2[key].IsShowed)
                        {
                            Deployment.Current.Dispatcher.BeginInvoke(() =>
                            {
                                dic2[key].Shown();
                            });
                        }
                    }
                }
            }

    这是第一次用的虚拟化,基本完全是遍历...之后设定是否显示...

    第二次的用的虚拟化稍微优化了一点...代码比较繁琐...

    基本思想就是判断目前的可视元素的顶部和底部...如果有元素出了屏幕或者进入屏幕就进行虚拟化或者显示出来...

    我觉得这应该是我能做到的最佳虚拟化方案了...但是实际还是不理想...

    async Task vi()
            {
                bool change = false;
    
                if (ScrollOffset < top1 || ScrollOffset + scrollViewer.ViewportHeight < top2)
                {
    
                    int m = 1;
                    while (true)
                    {
                        int i = Top1.IndexOf(up1);
                        if (i - m < 0)
                        {
                            break;
                        }
                        if (ItemList1[i - m].Key + ItemList1[i - m].Value.PostItemInfo.Height > ScrollOffset)
                        {
                            ItemList1[i - m].Value.Shown();
                            m++;
                            change = true;
    
                        }
                        else
                        {
                            break;
                        }
                    }
    
                    m = 1;
                    while (true)
                    {
                        int i = Top2.IndexOf(up2);
                        if (i - m < 0)
                        {
                            break;
                        }
                        if (ItemList2[i - m].Key + ItemList2[i - m].Value.PostItemInfo.Height > ScrollOffset)
                        {
                            ItemList2[i - m].Value.Shown();
                            m++;
                            change = true;
    
                        }
                        else
                        {
                            break;
                        }
                    }
    
                    m = 0;
                    while (true)
                    {
                        int i = Top1.IndexOf(down1);
                        if (i - m < 0)
                        {
                            break;
                        }
                        if (ItemList1[i - m].Key > ScrollOffset + scrollViewer.ViewportHeight)
                        {
                            ItemList1[i - m].Value.Hiden();
                            m++;
                            change = true;
    
                        }
                        else
                        {
                            break;
                        }
                    }
    
                    m = 0;
                    while (true)
                    {
                        int i = Top2.IndexOf(down2);
                        if (i - m < 0)
                        {
                            break;
                        }
                        if (ItemList2[i - m].Key > ScrollOffset + scrollViewer.ViewportHeight)
                        {
                            ItemList2[i - m].Value.Hiden();
                            m++;
                            change = true;
    
                        }
                        else
                        {
                            break;
                        }
                    }
                    
                }
                else if (ScrollOffset + scrollViewer.ViewportHeight > top3 || ScrollOffset > top0)
                {
                    int m = 0;
                    while (true)
                    {
                        int i = Top1.IndexOf(up1);
                        if (i + m == ItemList1.Count)
                        {
                            break;
                        }
                        if (ItemList1[i + m].Key + ItemList1[i + m].Value.PostItemInfo.Height < ScrollOffset)
                        {
                            ItemList1[i + m].Value.Hiden();
                            m++;
                            change = true;
                        }
                        else
                        {
                            break;
                        }
                    }
    
                    m = 0;
                    while (true)
                    {
                        int i = Top2.IndexOf(up2);
                        if (i + m == ItemList2.Count)
                        {
                            break;
                        }
                        if (ItemList2[i + m].Key + ItemList2[i + m].Value.PostItemInfo.Height < ScrollOffset)
                        {
                            ItemList2[i + m].Value.Hiden();
                            m++;
                            change = true;
                        }
                        else
                        {
                            break;
                        }
                    }
    
                    m = 0;
                    while (true)
                    {
                        int i = Top1.IndexOf(down1);
                        if (i + m == ItemList1.Count)
                        {
                            break;
                        }
                        if (ItemList1[i + m].Key < ScrollOffset + scrollViewer.ViewportHeight)
                        {
                            ItemList1[i + m].Value.Shown();
                            m++;
                            change = true;
                        }
                        else
                        {
                            break;
                        }
                    }
    
                    m = 0;
                    while (true)
                    {
                        int i = Top2.IndexOf(down2);
                        if (i + m == ItemList2.Count)
                        {
                            break;
                        }
                        if (ItemList2[i + m].Key < ScrollOffset + scrollViewer.ViewportHeight)
                        {
                            ItemList2[i + m].Value.Shown();
                            m++;
                            change = true;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                if (change == true)
                {
                    refreshTop();
                }
    
            }

    目前,我在尝试自己重写VirtualizingStackPanel或者VirtualizingPanel,但是目前还是没有什么头绪,主要是不知道他们是怎样工作的...

    网络上面也没有找到类似的实例...如果能告诉我VirtualizingStackPanel是如何进行排版,虚拟化,实例化,说不定就能搞定

    可惜看不到VirtualizingStackPanel的源码...如果能看懂VirtualizingStackPanel...写一个WaterFallVirtualizingPanel应该不是问题
    • 已编辑 HIGAN 2014年12月24日 8:40 添加说明
    2014年12月24日 8:36
  • 嗯...还真找到了VirtualizingStackPanel的源码...只不过是WPF的...可以用用来好好研究一下子了...

    .Net开源...真是一件...大快所有开发者的大好事...2333

    http://referencesource.microsoft.com/#PresentationFramework/Framework/System/Windows/Controls/VirtualizingStackPanel.cs,22e1b692280b25fa


    • 已编辑 HIGAN 2014年12月24日 15:03 加入源码链接
    2014年12月24日 15:00
  • 嗯...还真找到了VirtualizingStackPanel的源码...只不过是WPF的...可以用用来好好研究一下子了...

    .Net开源...真是一件...大快所有开发者的大好事...2333

    http://referencesource.microsoft.com/#PresentationFramework/Framework/System/Windows/Controls/VirtualizingStackPanel.cs,22e1b692280b25fa



    你好,

    看你的虚拟化方法应该是计算可视区域,控制显隐藏,这样确实可以,但是效率有些低,使用一些支持虚拟化的控件应该会好很多。

    .Net的开源确实帮助我们理解和重写控件,希望可以顺利写出瀑布流布局的布局控件:)


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    2014年12月25日 9:59
    版主