Search Unity

Optimized ScrollView Adapter + Playmaker support

Discussion in 'Assets and Asset Store' started by xucian, Apr 1, 2016.

  1. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    v2.5 just went live with major improvements, bugfixes & features! :D
    The code reference was also extended to include everything + migrated online (can be accessed via Unity's menu bar).
    Please see release notes if updating from a previous version!
     
    rattlesnake likes this.
  2. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Now supporting Content Size Fitter for items of unknown size at init time!
    Example scene & code included
    (Also please check release notes)
     
  3. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,462
    Very nice project.
    Does this support drag and drop
     
  4. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Hi.
    Nope. This has nothing to do with a scroll view. At last, not in the way I imagine it
     
  5. anovice

    anovice

    Joined:
    Mar 24, 2013
    Posts:
    2
    Great asset.

    I'm playing around with simple_tutorial and noticed this issue when trying to animate various elements of the prefab, after initial instantiation. This repeats over and over again. When resizing the canvas, this result shifts to different prefab instances.

    Is there a way to change the appearance of instance prefabs without affecting other instance prefabs. I'm assuming this is part of the overall optimization, so also hoping for advice on best practice.

    Thanks in advance! :)

     
  6. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Hello.
    Thanks for using our asset :)

    As you've correctly assumed, the views are recycled, so ideally there won't be any context in which you would change them directly, without letting the adapter know.

    It really depends on what your animation is doing. A very good example on how would you "ask [the optimizer] for" animating an item is found in the very scene you're playing with (simple_tutorial): when you click an item, it expands/shrinks. Its associated model has an "expanded" boolean property, which changes based on the state. And this makes all the views consistent with their state, even though 10 views are continuously recycled to display 10000 items. UpdateViewsHolder is called each time an item is made visible, and so its view is always in sync with whatever model should be displayed at that position.
    In this case, a size change also needs to inform (actually, ask for it) the adapter each frame of the animation. This is very well exemplified together with ExpandCollapseOnClick utility.

    As a general rule, any visual modification that should persist should be stored somewhere. Storing it in your data model is the most easy way of doing it. Don't create separate arrays, as they are hard to manage.

    Dig a bit more into it and if you still need guidance, give me a more detailed explanation of what the animation should do.

    Best,
    Lucian
     
  7. anovice

    anovice

    Joined:
    Mar 24, 2013
    Posts:
    2
    Wonderful! Thank you so much. :)

    I'm glad I'm on the right track.
     
  8. ywj7931

    ywj7931

    Joined:
    Jun 24, 2015
    Posts:
    41
    Hello, in demo, in the vertical scroll view, I see I can expand a item view, so the bottom can be squeezed down. I wonder if it is supported that if I expand a item, both above and bottm item views will be squeezed?

    Thanks
     
  9. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Hi.
    Not currently supported, but I wrote that down for a future release. You can only specify if it can grow towards the end(like in the demo) or towards the start.

    Lucian
     
  10. KeiseEntertainment

    KeiseEntertainment

    Joined:
    May 5, 2015
    Posts:
    23
    Hi there.

    Could you help me with 2 questions i have?

    1- Is there a way i could resize my Prefab Items with "scale" property and not "width" or "height" so all the Scroll respect padding and re-do the layout?
    2- Is there a way i could fix the "width" or "height" of my element? I have a Vertical Scroll and my Prefab Items "width" always expands 100% of my "content".

    Thank you =]

    Felipe.
     
  11. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    1. I don't think so. Scaling should usually be used for aesthetic purposes, not functional - this is strictly my opinion, like an unwritten rule of thumb. Tell me why you don't want to scale instead + more details. Maybe I'll see a solution

    2. The items will always expand in width (in case of vertical scroll), respecting any padding of course. Use an intermediary element so that its child will be your actual item. The parent expands, but the child will have a fixed width (use anchors for that). Or make each "item container" a layout group and the actual item a LayoutElement and set it a fixed size. It really depends on how many screens are you targeting and how does your scrollview resize according to the screen

    Lucian
     
  12. KeiseEntertainment

    KeiseEntertainment

    Joined:
    May 5, 2015
    Posts:
    23
    I was able to do what i wanted with solution number 2. About number 1, i wanted to use "scale" instead because i didn't want to recalculate every anchors, width and height of my prefab childrens... But with solution 2 + canvas scale + a little of solution 1 i was able to get what i wanted =]

    Thank you for the support.

    Felipe.
     
    xucian likes this.
  13. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Awesome! ;)
    Have fun!
     
  14. ywj7931

    ywj7931

    Joined:
    Jun 24, 2015
    Posts:
    41
    We want to modify the plugin, so that the item icon will scale down or up based on its index. So basically I just need to change it when the item's index changes in the visible scroll view. For example, the first item visible in the scroll view will have index 0, if it become second row of visible items, when its index become 1, we perform the scale change. Could you please tell us where is the best place in the code to check? Thanks
     
  15. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Hi. I need a more detailed explanation. Images showing the behavior would be easier to grasp
     
  16. ywj7931

    ywj7931

    Joined:
    Jun 24, 2015
    Posts:
    41
    For example, in our UI, it is like a wheel, the mid one has the largest size. So I want to fit this UI into your scroll view plugin. So basically, I just need to change item's size and position when its visible index changes. IS that clear?
     

    Attached Files:

  17. MrIconic

    MrIconic

    Joined:
    Apr 5, 2013
    Posts:
    239
    Question: Is there any way to add a single itemprefab to the existing MyScrollRect without recalculating everything before where it is placed (at the end).?

    --

    After changing some things I've created a chatbox. I can load data with any height variation into the chatbox and scroll it.

    However, I now want to add new entries at the end of the chatbox. I added some initial values using UpdateItems() and then used the method below.

    Code (csharp):
    1.  
    2.        public void addItem(string messageToAdd) {
    3.  
    4.            _Data.Capacity++;
    5.          
    6.           _Data.Add(new SampleObjectModel("-2", "-2","System",messageToAdd));
    7.          
    8.          
    9.           _ScrollRectItemsAdapter.ChangeItemCountTo(_Data.Capacity);
    10.        }
    11.  
    Yet, everytime I use addItem() the existing ItemPrefabs seem to recalculate their positions. As if it's recreating the layout not from a cache. This isn't necessary because I'm adding (literally) to the end of the list/scroll.
     
    Last edited: Jul 17, 2017
  18. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    You can look into ExpandOnClick & how it's used in the example scenes. You have access to the current visible items array and this can be used in an Update function to constantly change their size based on their visual position relative to the viewport (bonus: they're already sorted in the order they appear visually).
    Please let me know if you succeed and if the final performance is acceptable. I'm also interested to see the result.
     
  19. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    _Data.Capacity ? maybe you meant _Data.Count?
    Please correct your code and let me know if this solves it :)
     
  20. ywj7931

    ywj7931

    Joined:
    Jun 24, 2015
    Posts:
    41
    I checked ExpandCollapseOnClick.cs, but didn't find relevant script for visible items, which parameter should I search for?
     
  21. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    There's only the mechanism for requesting a "size change" from the adapter.
    You'd use GetItemViewsHolder to iterate (from 0 to VisibleItemsCount-1) through all visible view holders and request a size change for each of them.
    Beware that when an item's size changes, the VisibleItemsCount may also change, so do not store VisibleItemsCount into a variable + you should also compensate from this by additionally incrementing/decrementing your iterator on-the-go in case when, for example, the second item actually became the first one (in case you're resizing by keeping the item's "end" edge stationary, instead of the default method - see RequestChangeItemSizeAndUpdateLayout).

    A very simplistic start point would be something like:

    int i = 0;
    while(i < adapter.VisibleItemsCount)
    {
    vh = adapter.GetItemViewsHolder(i);
    adapter.RequestChangeItemSizeAndUpdateLayout(vh, <size>);
    ++i;
    }

    You should be aware that by changing the sizes, the items will naturally shift to the end (or to the start, if you supply the third optional parameter of RequestChangeItemSizeAndUpdateLayout as true), so you need to make some calculations to find out exactly what item should you resize as the "biggest" (I assume you want the biggest to be in the middle)

    Not tested, not benchmarked. Recalculates the layout each time a size change request is made.
    If the speed of this is not acceptable, try executing it less often (once per 5-10-20-30 frames).
    No optimizations can be done with ease and we don't look into adding this functionality to the package very soon. Sorry

    We can help you with any question about the optimizer and small changes, but if you need individual and/or extensive support with this, shoot at lucian@thefallengames.com

    Be well!
    George @ TFG
     
  22. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    I'll add here your emails, since it turned out you have a much simpler case than I thought:


    Well, first, both the root's scale and its scrollrect's size shouldn't ever be manipulated manually.
    Try this: make each item contain a child which contains all the views and then scale that child. You can make the root bigger, so that initially there's some padding inside it (to prevent overlapping).

    Lesson: Do whatever you like to the item's children, but don't you dare touching the root :D

    Second issue: there'll always be one item enabled outside the viewport, so it'll be ready to be rendered before it'll appear. You can compensate for this by ignoring it. Take a look again to my previous reply to understand how to iterate through all the visible ones.

    Third issue: You cannot change the adapter's VisibleItems array, but you can choose what items to scale. You need a method to find out how to detect if an item is outside the mask or not or something like this, which is totally out of this thread's scope, so I can't really help you with an easy solution

    Happy coding!
    George @ TFG
     
  23. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
  24. dbthegame

    dbthegame

    Joined:
    Aug 5, 2017
    Posts:
    1
    Hi. this plugin looks really interesting, I tried the wrbGL demo and I'm surprised with the results in terms of performance.
    Definitely buy it, but first I have some question:
    a) we are currently using this extension: https://bitbucket.org/ddreaper/unity-ui-extensions/wiki/Controls/ScrollRectEx . will it interfere with this plugin?
    b) is the scrollview 100% functioning if we rotate it like in the image below?


    Thanks
     
  25. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Hi.

    a) not at all. the adapter doesn't extend the ScrollRect class. Its core fuctionality lies in a plain c# class which you extend to provide your custom implementation (there are plenty of example scripts/scenes) and it only needs a reference to your ScrollRect and some parameters. This gives you a lot of flexibility.

    b) yes. You can rotate/scale it without any problem.

    Have fun :)
    Lucian
     
  26. sea129

    sea129

    Joined:
    Mar 29, 2017
    Posts:
    4
    Thanks for this nice package.
    I have a problem which is similar to what 2011drevil mentioned to add more items fetched from server while scrolling. I can manage to add more items, everything is fine, however, after it updates, items are shifted up, it seems that old items lost their positions. here is example code, hope you can understand. And could you provide an simple example for adding new items while scrolling?
    Code (CSharp):
    1.  
    2. private void Update()
    3. {
    4.        if (_ScrollRect.verticalNormalizedPosition < 0.25f && !isUpdating && !this.isEnd)
    5.        {
    6.            UpdateItems();
    7.        }
    8. }
    9. private void UpdateItems(){
    10.     //request server to get more items and call
    11.     OnReceivedItems(items);
    12. }
    13. private void OnReceivedItems(items){
    14.     adapterParams.data.AddRange(items);
    15.     _Adapter.ChangeItemCountTo(adapterParams.data.Count);
    16. }
    17.  
     
    Last edited: Aug 14, 2017
  27. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Hi

    Check this script example (it's tested and it'll be included together in its own example scene in the next minor release, in a few days):

    Note that it's more accurate to check for the index of the last visible item than simply for the scroll position

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4. using System;
    5. using System.Collections.Generic;
    6. using frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter;
    7.  
    8. namespace frame8.ScrollRectItemsAdapter.IncrementalItemFetchExample
    9. {
    10.     /// <summary>
    11.     /// IMPORTANT NOTE: Only use this approach if it's impossible to know the total number of items in advance or there's simply too much overhead.
    12.     ///    If the number of items IS known, consider using placeholder prefabs with a "Loading..." text on them (which also makes a nicer UX!) while they're being downloaded/processed.
    13.     ///    The placeholder approach is implemented in <see cref="GridExample.GridExample"/> - be sure to check it out.
    14.     ///
    15.     /// This class demonstrates how items can be appended at the bottom as needed (i.e. when the user acually scrolls there), as opposed to directly downloading all of them.
    16.     /// This is useful if the number of items can't be known beforehand (because of reasons)
    17.     /// </summary>
    18.     public class IncrementalItemFetch : MonoBehaviour
    19.     {
    20.         /// <summary>Configuration visible in the inspector</summary>
    21.         public MyParams adapterParams;
    22.  
    23.         // Instance of your ScrollRectItemsAdapter8 implementation
    24.         MyScrollRectAdapter _Adapter;
    25.         bool _Fetching;
    26.  
    27.  
    28.         void Start()
    29.         {
    30.             _Adapter = new MyScrollRectAdapter();
    31.             Canvas.ForceUpdateCanvases();
    32.  
    33.             _Adapter.Init(adapterParams);
    34.  
    35.             //// Need to initialize adapter after a few frames, so Unity will finish initializing its layout
    36.             //StartCoroutine(DelayedInit());
    37.         }
    38.  
    39.         void Update()
    40.         {
    41.             //if (_Adapter.Parameters == null) // i.e. not initialized yet (because the initialization is delayed)
    42.             //    return;
    43.  
    44.             if (_Fetching)
    45.                 return;
    46.  
    47.             int lastVisibleItemitemIndex = -1;
    48.             if (_Adapter.VisibleItemsCount > 0)
    49.                 lastVisibleItemitemIndex = _Adapter.GetItemViewsHolder(_Adapter.VisibleItemsCount - 1).itemIndex;
    50.             int numberOfItemsBelowLastVisible = adapterParams.data.Count - (lastVisibleItemitemIndex + 1);
    51.  
    52.             // If the number of items available below the last visible (i.e. the bottom-most one, in our case) is less than <adapterParams.preFetchedItemsCount>, get more
    53.             if (numberOfItemsBelowLastVisible < adapterParams.preFetchedItemsCount)
    54.             {
    55.                 int newPotentialNumberOfItems = adapterParams.data.Count + adapterParams.preFetchedItemsCount;
    56.                 if (adapterParams.totalCapacity > -1) // i.e. the capacity isn't unlimited
    57.                     newPotentialNumberOfItems = Mathf.Min(newPotentialNumberOfItems, adapterParams.totalCapacity);
    58.  
    59.                 if (newPotentialNumberOfItems > adapterParams.data.Count) // i.e. if we there's enough room for at least 1 more item
    60.                     StartPreFetching(newPotentialNumberOfItems - adapterParams.data.Count);
    61.             }
    62.         }
    63.  
    64.         void OnDestroy()
    65.         {
    66.             // The adapter has some resources that need to be disposed after you destroy the scroll view
    67.             if (_Adapter != null)
    68.                 _Adapter.Dispose();
    69.         }
    70.  
    71.         // Initialize the adapter after 3 frames
    72.         // You can also try calling Canvas.ForceUpdateCanvases() instead if you for some reason can't wait 3 frames, although it wasn't tested
    73.         IEnumerator DelayedInit()
    74.         {
    75.             // Wait 3 frames
    76.             yield return null;
    77.             yield return null;
    78.             yield return null;
    79.  
    80.             _Adapter.Init(adapterParams);
    81.         }
    82.  
    83.         public void UpdateCapacity()
    84.         {
    85.             int newCapacity = int.Parse(adapterParams.capacityText.text);
    86.             if (newCapacity < adapterParams.data.Count)
    87.                 adapterParams.capacityText.GetComponentInParent<InputField>().text = adapterParams.data.Count + "";
    88.             else
    89.                 adapterParams.totalCapacity = newCapacity;
    90.         }
    91.  
    92.         // Setting _Fetching to true & starting to fetch
    93.         void StartPreFetching(int additionalItems)
    94.         {
    95.             _Fetching = true;
    96.             StartCoroutine(FetchItemModelsFromServer(additionalItems, OnPreFetchingFinished));
    97.         }
    98.  
    99.         // Updating the models list and notify the adapter that it changed;
    100.         // it'll call GetItemHeight() for each item and UpdateViewsHolder for the visible ones.
    101.         // Setting _Fetching to false
    102.         void OnPreFetchingFinished(ExampleItemModel[] models)
    103.         {
    104.             adapterParams.data.AddRange(models);
    105.             var vel = adapterParams.scrollRect.velocity; // get the current velocity, as the
    106.             _Adapter.ChangeItemCountTo(adapterParams.data.Count);
    107.             adapterParams.scrollRect.velocity = vel;
    108.             adapterParams.statusText.text = adapterParams.data.Count + " items";
    109.             _Fetching = false;
    110.         }
    111.  
    112.         IEnumerator FetchItemModelsFromServer(int count, Action<ExampleItemModel[]> onDone)
    113.         {
    114.             adapterParams.statusText.text = "Fetching "+ count + " from server...";
    115.  
    116.             // Simulating server delay
    117.             yield return new WaitForSeconds(.5f);
    118.  
    119.             // Generating some random models
    120.             var results = new ExampleItemModel[count];
    121.             for (int i = 0; i < count; ++i)
    122.             {
    123.                 results[i] = new ExampleItemModel();
    124.                 results[i].title = "Item got at " + DateTime.Now.ToString("hh:mm:ss");
    125.             }
    126.  
    127.             onDone(results);
    128.         }
    129.  
    130.  
    131.         // This is your model
    132.         [Serializable]
    133.         public class ExampleItemModel { public string title; }
    134.  
    135.  
    136.         #region ScrollRectItemsAdapter8 code
    137.         // This in almost all cases will contain the prefab and your list of models
    138.         [Serializable] // serializable, so it can be shown in inspector
    139.         public class MyParams : BaseParams
    140.         {
    141.             public RectTransform prefab;
    142.  
    143.             public Text statusText, capacityText;
    144.             public int preFetchedItemsCount;
    145.             [Tooltip("Set to -1 if while fetching <preFetchedItemsCount> items, the adapter shouldn't check for a capacity limit")]
    146.             public int totalCapacity;
    147.  
    148.             public List<ExampleItemModel> data = new List<ExampleItemModel>();
    149.         }
    150.  
    151.         // Self-explanatory
    152.         public class MyItemViewsHolder : BaseItemViewsHolder
    153.         {
    154.             public Text titleText;
    155.  
    156.  
    157.             public override void CollectViews()
    158.             {
    159.                 base.CollectViews();
    160.  
    161.                 titleText = root.Find("TitleText").GetComponent<Text>();
    162.             }
    163.         }
    164.  
    165.         /// <summary>The custom adapter implementation that'll manage the list of items using rules customized for our use-case</summary>
    166.         public class MyScrollRectAdapter : ScrollRectItemsAdapter8<MyParams, MyItemViewsHolder>
    167.         {
    168.             // Will be called for vertical scroll views
    169.             protected override float GetItemHeight(int index) { return _Params.prefab.rect.height; }
    170.  
    171.             // Will be called for horizontal scroll views
    172.             protected override float GetItemWidth(int index) { return _Params.prefab.rect.width; }
    173.  
    174.             /// <summary>See <see cref="ScrollRectItemsAdapter8{TParams, TItemViewsHolder}.CreateViewsHolder(int)"/></summary>
    175.             protected override MyItemViewsHolder CreateViewsHolder(int itemIndex)
    176.             {
    177.                 var instance = new MyItemViewsHolder();
    178.                 instance.Init(_Params.prefab, itemIndex);
    179.  
    180.                 return instance;
    181.             }
    182.  
    183.             /// <summary>See <see cref="ScrollRectItemsAdapter8{TParams, TItemViewsHolder}.UpdateViewsHolder(TItemViewsHolder)"/></summary>
    184.             protected override void UpdateViewsHolder(MyItemViewsHolder newOrRecycled)
    185.             {
    186.                 // Initialize the views from the associated model
    187.                 ExampleItemModel model = _Params.data[newOrRecycled.itemIndex];
    188.  
    189.                 newOrRecycled.titleText.text = "[" + newOrRecycled.itemIndex + "] " + model.title;
    190.             }
    191.         }
    192.         #endregion
    193.  
    194.     }
    195. }
    196.  
     
  28. sea129

    sea129

    Joined:
    Mar 29, 2017
    Posts:
    4
    Hi
    Thank you for the example.
    I have tried it. It works when you do one touch/drag scroll, I can see that new items added to bottom and content height increases. but if you do hold and drag, during the time of drag, if there are new items added to bottom, again items shifted up. Because the height of content increases, it seems trying to shift to the old position.

    Can you try it on that example that you have build? Thank you very much
     
  29. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    You really have a one-of-a-kind setup, aren't you? :)
    Thi script works silky smooth on a simple example, with a fixed-height prefab (althought I'm 99% sure it also works with arbitrary heights).
    So it seems like your example worked from the beginning and didn't need my example at all, because the shifting problem is elsewhere.
    If everything's set up right, the adapter should behave as expected, not with these 'jumps'

    Let's see..
    In comparison to the vanilla simple scene, can you tell me what is different (both in the scripts and in the scene) ? In general. Also, if there are a lot of changes, make sure you strip theproject to be <50mb (I'm on a metered connection for 10days) and send me a link via email. I'll take a look

    Best,
    Lucian
     
    sea129 likes this.
  30. sea129

    sea129

    Joined:
    Mar 29, 2017
    Posts:
    4
    I made a silly mistake, Pivot of Content should be set to the top (0.5, 1), I set it to middle which causes the shifting when content gets longer.

    Really appropriate for the support.
     
  31. sea129

    sea129

    Joined:
    Mar 29, 2017
    Posts:
    4
    It is me again.
    For the incrementalItemFetch example, I tried with loading images inside each item. When Scroll Content gets longer, I noticed that image inside view holder flashes(flicking / switching). I think that is because image is updated since the position of view holder changes. It also happens to the text but hard to be noticed. Do you have any ideas how to solve this? Or I did some thing wrong again.
     
    Last edited: Aug 17, 2017
  32. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Glad you figured out the first issue. :)
    I'll note in the instructions doc that the pivot should always be set up like that so no one will fall into this problem anymore.

    Async loading is a bit tricky here if you're not used to it. There are quite a lot of things to manage. Fortunately, this is fully exemplified in the grid example and it's also very well optimized to make as few network calls as possible.
    Take a look and come back if you get stuck somewhere :)

    Lucian
     
  33. Lasse-Loepfe

    Lasse-Loepfe

    Joined:
    Mar 28, 2014
    Posts:
    29
    Hi, congrats for a nice product.
    Just wanted to give the snap functionality some user-feedback-power ;)
     
  34. JoeriVDE

    JoeriVDE

    Joined:
    Jan 28, 2015
    Posts:
    6
    Hi, first of all: great tool and great documentation/examples. It was very easy to modify it to our needs and implement it in our app(s). So bravo for that!

    One question though: we would like to have the items that are visible (in other words, the item's that are (being) loaded) to exceed the range of the scrollrect viewport. Example: the viewport fits 4 - 5 items (with item 1 and 5 being cut off by the viewport edges). One of these may be inactive or ready to be recycled and reused. We would like to have say 7 to 8 items loaded (and active) to prevent image loading gaps when scrolling slowly. Is there a way to do this in the plugin?

    I've already tried to increase the Params property 'minNumberOfObjectsToKeepInMemory' but that doesn't seem to do the trick for us. It's not a necessity but any help would be welcome.

    Thanks in advance!
     
  35. TonkRogerio

    TonkRogerio

    Joined:
    Apr 12, 2013
    Posts:
    15
    Hi. I'm not a coder, I use playmkaer. I'm not sure if this will do what I want it to so I'm not sure if I'm buying yet because I don't want to waste my money.

    My menu comes with game objects with data on them. they generate the data when activated and then they store that data until they are no longer needed. Think of like football manager hiring footballers menu for example.
    So the way this works from my understanding is that it recycles the game objects as you scroll. but if that's the case then the data from the one recycled will be the same as the next game object, right?
    I'm not sure if I'm making myself clear but I can't really buy until I understand this part.

    Also how easy will this be to use with playmkaker? do you know? will I need to code in order to make it work?

    Thanx for your time.
     
  36. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Hi :)
    Sorry for the late replies (mini-vacation)

    Thanks! Brought it upper on the to-do list! :)


    Yes, we'll add this into the next release (which will be uploaded in ~1 week).
    Please send me an email at lucian@thefallengames.com with this request and with your invoice number and you'll get the necessary instructions about what code to add/change and where in order to have this functionality, so you won't need to wait until the next official release :)
    Have a nice day!


    Hi.

    You can test the WebGL demo on a PC to see if it suits your needs.
    But we won't support playmaker too soon. ATM, there's code to be written, inevitably, because we made it so that it'll work in as much contexts as possible. In v3.0 we'll provide a solution (a sub-package, I guess) for non-coders to also use it, with a performance & flexibility trade-off, of course.
    Only after this we can move forward and implement support for playmaker.
    This is our main asset and it's on active development. Because it's such a necessary plugin (we saw a rapid growth in downloads since v2.0), we'll actively work on improving it and providing new features, especially the requested ones.
    As a very rough estimation, I guess playmaker support will come in about 6 months.

    Thanks also for your time and hope to see you again!
    :D:D

    Lucian
     
  37. niaobudirtybit

    niaobudirtybit

    Joined:
    Jun 10, 2015
    Posts:
    3
    Hi!
    Happy user of the plugin so far.
    Feedback: I thought the documentation was lacking a short explanation of the different components, especially the ViewsHolder and surrounding logic. The code and comments mix singular ViewHolder and plural ViewsHolder. (Example: BaseItemViewsHolder extends AbstractViewHolder) Do these components hold multiple views? At the same time? Or is this referring to the fact that they are recycled? Finally there is no definition or clarification on what a view is :p

    Question: In the MultiplePrefabs example with expandable prefabs, is there a nice and clean way to make the expandable rows work as radio buttons, that is only one can be expanded at a time? Ideally, clicking one row would cause the last to collapse (still animating smoothly) even if it is not on screen. Any ideas?

    Thanks,
    Niaobu
     
  38. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Hi Niaobu!
    You know what? You're right! I was really bothered by this discrepancy too from the beginning, but never thought it'll also bother anyone else, plus the fact that fixing this would be done by creating another class(+file) AbstractViewsHolder while also keeping the old AbstractViewHolder with the System.Obsolete attribute on it so that those that update from the current version would have a neat transition.
    I've just did this, but also renamed all occurrences of the "view holder" (and all of its variations) so that they'll have the plural "views".
    So there's no more View Holder, but Views Holder.
    And it simply means the holder holds the views of an item. It has always meant that. Hopefully, there won't be any confusion anymore.

    Ok, moving forward to your last question:
    In the current official version, there's no way of calling RequestChangeItemSizeAndUpdateLayout for a non-visible item.
    But I've just included one today and also changed the multiple prefabs example to have this very behavior you need.
    You have every detail in the example script.

    Shoot me an email with your invoice number & I'll give you an early access package with these changes.

    Wish you an awesome day :)
    Lucian
     
  39. KeiseEntertainment

    KeiseEntertainment

    Joined:
    May 5, 2015
    Posts:
    23
    Hi there.. Its me again =]

    I have a question about constantly updating scroll list items values. I have a scroll list with user game statistics, and there is some numbers i want to update every second.

    Actually i've accomplished that that with "_Adapter.Refreh()" but i got a small "problem". If the user is scrolling the list and "Refresh()" is called, the list just stop scrolling doesn't keeping giving the smooth effect.

    And the "Refresh()" method recalculate extra things that i don't need either (like new item number count, new content size, etc..). Is there a way that can constantly update only the items values without compromising the scrolling effects?

    Thank you for the support =]

    Felipe.
     
  40. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Hi. Yes. The easiest solution that came into my mind is to have an UpdateVisibleItemsNow() method where you iterate from 0 to VisibleItemsCount - 1, use GetItemViewsHolder and update it the same way you're doing it in Adapter.UpdateItemViewsHolder callback - you can even call UpdateItemViewsHolder yourself for each viewsHolder you get in order to re-use the code in there ;)
    Call it whenever you make a change, or in an MonoBehaviour.Update() if changes cannot be tracked immediately as they are made.

    Hope that helps :)
    Lucian


    The v3.0 version is the biggest change-set so far and it's around the corner. It will have this utility method in it so you won't need to implement it yourself, but it may take 1 or 2 more weeks until then and it won't be easily compatible with the current version
     
    KeiseEntertainment likes this.
  41. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Pre-release info about v3.0 was included in the main post! :D
     
    KeiseEntertainment likes this.
  42. KeiseEntertainment

    KeiseEntertainment

    Joined:
    May 5, 2015
    Posts:
    23
    Wow! That worked perfectly!

    I create an "UpdateItem" method inside Item View Holder Class and did what you told:

    Code (CSharp):
    1.     public void UpdateStatistics()
    2.     {
    3.         //Debug.Log("UpdateStatistics()");
    4.         //_Adapter.Refresh();
    5.  
    6.         for (int i = 0, length = _Adapter.VisibleItemsCount; i < length; i++)
    7.         {
    8.             _Adapter.GetItemViewsHolder(i).UpdateItem();
    9.         }
    10.     }


    Thank you for the support and quick answer!

    Can't wait for version 3.0 o//

    Felipe.
     
    xucian likes this.
  43. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    The biggest update so far, v3.0, is alive with major changes & improvements! :D
    Be sure to make a backup before upgrading from a previous version, as 2.x and 3.0 aren't immediately compatible
     
  44. Jochanan

    Jochanan

    Joined:
    Nov 9, 2016
    Posts:
    85
    Hello @thefallengamesstudio, i have just downloaded v 3.0 and it looks great. I created a chat using v2, but the demo chat scene in v3 looks much better. Unfortunatelly, i am having an issue in my use case, where i have list of friends, which i can chat with and the chat component itself. I am having issues with switching between chat data.
    This is working
    Code (CSharp):
    1. _Params.Data.Clear();
    2.  
    3. // Generating some random models
    4. for (int i = 0; i < newCount; ++i)
    5.   _Params.Data.Add(CreateNewModel());
    6.  
    7. ResetItems(_Params.Data.Count, true);
    But this is not
    Code (CSharp):
    1. // Invalidate the last sizes so that they'll be re-calculated
    2. foreach (MessageContext model in rgpc.ChatReferenced.MessageItems)
    3.   model.HasPendingVisualSizeChange = true;
    4.  
    5. // Set new data
    6. this._Params.Data = rgpc.ChatReferenced.MessageItems;
    7.  
    8. ResetItems(_Params.Data.Count, true);
    It squezes all the messages and i have to scroll them outside the view to have them in their correct sizes.
    Chat.gif
    What i am doing wrong?

    EDIT: It was caused by that Component was not Active and Enabled in that time, so i changed it this way:
    Code (CSharp):
    1.  
    2. private void OnEnable()
    3. {
    4.   if (this.messagesToSet != null)
    5.   {
    6.     StartCoroutine(PropagateContextToSet(this.messagesToSet));
    7.     this.messagesToSet = null;
    8.    }
    9. }
    10.  
    11. private IEnumerator PropagateContextToSet(Collection<MessageContext> messagesToSet)
    12. {
    13.   // Invalidate the last sizes so that they'll be re-calculated
    14.   foreach (MessageContext model in messagesToSet)
    15.     model.HasPendingVisualSizeChange = true;
    16.  
    17.    // Set new data
    18.    this._Params.Data = messagesToSet;
    19.  
    20.    yield return new WaitForEndOfFrame();
    21.    // Reset in the next frame...
    22.  
    23.    ResetItems(_Params.Data.Count, true);
    24. }
     
    Last edited: Oct 6, 2017
  45. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Hi.

    Reset() does everything instantly, including calling UpdateViewsHolder(), so first try setting haspending=true before it. But a better way would be to do it in the Reset(override it, do the changes you need and call base.Reset() at end).
    You don't need to wait a frame or anything like that (except if your other components need that).

    Important tip: if you're just appending items, take a look at InsertItems(), which saves immense CPU time in this case.
    It's also exemplified in the demos

    Happy coding :)
     
  46. KeiseEntertainment

    KeiseEntertainment

    Joined:
    May 5, 2015
    Posts:
    23
    Hi there,

    First of all, great work you did in the newest version! xD

    And now here are my questions. Both of them are about Grid (used "GridExample" as reference).

    Question #01 - Is there a way to use Multiple Prefabs with Grid? What i'm doing is some kind of "Gallery", so loads every saved "item" of the user, but this item could be any item from my game (some "items" has diferents properties and script, so, diferents prefabs). One solution i thought is to create one "Master Prefabs" that contains all "items" and activate/deactivate the parts i need for that cell, but i don't think that is a good solution...

    Question #02 - If i open my "Gallery" (explained in Question #01) and there is no "item" to load, the Grid is initialized with "0" cels, so far so good. But if after that i save some "item" and open "Gallery" again, 2 errors occours.

    ps: If i open the Gallery for the first time and there is "items" saved, everything works as it should.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4. using TMPro;
    5. using CodeStage.AntiCheat.ObscuredTypes;
    6. using frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter;
    7. using frame8.ScrollRectItemsAdapter.Util.GridView;
    8. using System;
    9. using frame8.Logic.Misc.Other.Extensions;
    10.  
    11. /// <summary>Minimal implementation of the adapter that initializes & updates the viewholders. The size of each item is fixed in this case and it's the same as the prefab's</summary>
    12. public class GalleryGridScrollView : GridAdapter<GridParams, GridViewsHolder>
    13. {
    14.     public static GalleryGridScrollView instance;
    15.  
    16.     private bool isInitialized = false;
    17.  
    18.     #region GridAdapter implementation
    19.     /// <inheritdoc/>
    20.     protected override void Awake()
    21.     {
    22.         base.Awake();
    23.  
    24.         instance = this;
    25.     }
    26.  
    27.     /// <inheritdoc/>
    28.     protected override void Start()
    29.     {
    30.         base.Start();
    31.  
    32.         isInitialized = true;
    33.         ResetItems(PlayerDataManager.instance.models.Count);
    34.     }
    35.  
    36.     private void OnEnable()
    37.     {
    38.         //Verifica se o script já foi inicializado.
    39.         if (!isInitialized)
    40.             return;
    41.  
    42.         Debug.Log("GalleryGridScrollView.OnEnable()");
    43.         ResetItems(PlayerDataManager.instance.models.Count);
    44.  
    45.         ////Verifica possui algum modelo salvo a ser carregado. Pular a inicialização caso seja 0 para evitar bugs.
    46.         //if (PlayerDataManager.instance.models.Count > 0)
    47.         //{
    48.         //    Debug.Log("PlayerDataManager.instance.models.Count > 0");
    49.         //    //Verifica se o script já foi inicializado.
    50.         //    if (!isInitialized)
    51.         //    {
    52.         //        Debug.Log("!isInitialized");
    53.         //        base.Awake();
    54.         //        base.Start();
    55.         //        isInitialized = true;
    56.         //    }
    57.  
    58.         //    ResetItems(PlayerDataManager.instance.models.Count);
    59.         //}
    60.     }
    61.  
    62.     /// <summary> Called when a cell becomes visible </summary>
    63.     /// <param name="viewsHolder"> use viewsHolder.ItemIndexto find your corresponding model and feed data into its views</param>
    64.     protected override void UpdateCellViewsHolder(GridViewsHolder newOrRecycled)
    65.     {
    66.         //newOrRecycled.button.onClick.RemoveAllListeners();
    67.         //newOrRecycled.button.onClick.AddListener(() => { TopScrollView.instance.SelectCategory(newOrRecycled.ItemIndex); });
    68.  
    69.         ModelSettings modelSettings = PlayerDataManager.instance.models[newOrRecycled.ItemIndex];
    70.         newOrRecycled.background.sprite = Resources.Load<Sprite>(string.Format("Sprites/Backgrounds/Backgrounds/{0}", modelSettings.background));
    71.  
    72.         switch (modelSettings.model)
    73.         {
    74.             case GameManager.Models.PUMPKIN:
    75.                 newOrRecycled.pumpkinModel.SetModelSettings(modelSettings.modelData);
    76.                 break;
    77.         }
    78.     }
    79.     #endregion
    80. }
    81.  
    82. // Self-explanatory
    83. public class GridViewsHolder : CellViewsHolder
    84. {
    85.     public Button button;
    86.     public Image background;
    87.  
    88.     public PumpkinModel pumpkinModel;
    89.  
    90.     public override void CollectViews()
    91.     {
    92.         base.CollectViews();
    93.  
    94.         button = views.GetComponent<Button>();
    95.         views.GetComponentAtPath("Background", out background);
    96.         views.GetComponentAtPath("PumpkinModel", out pumpkinModel);
    97.     }
    98.     protected override RectTransform GetViews() { return root.Find("Views") as RectTransform; }
    99. }
    100.  

    Code (CSharp):
    1. Can't add a 'RectTransform' to the "GalleryGridScrollView_GridAdapter_GroupPrefab" game object during Awake when a 'Transform' is already attached.
    2. You probably need to add a 'RectTransform' to the "GalleryGridScrollView_GridAdapter_GroupPrefab" game object in the editor.
    3. UnityEngine.GameObject:AddComponent()
    4. frame8.ScrollRectItemsAdapter.Util.GridView.GridParams:GetGroupPrefab(Int32) (at Assets/SRIA/Scripts/Util/GridView/GridParams.cs:65)
    5. frame8.ScrollRectItemsAdapter.Util.GridView.GridAdapter`2:CreateViewsHolder(Int32) (at Assets/SRIA/Scripts/Util/GridView/GridAdapter.cs:163)
    6. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ComputeVisibility(Double) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:1080)
    7. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ComputeVisibilityForCurrentPosition(Boolean, Boolean, Boolean) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:434)
    8. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ComputeVisibilityForCurrentPosition(Boolean, Boolean, Boolean, Double) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:413)
    9. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ChangeItemsCountInternal(ItemCountChangeMode, Int32, Int32, Boolean, Boolean) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:315)
    10. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ChangeItemsCount(ItemCountChangeMode, Int32, Int32, Boolean, Boolean) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIA.cs:175)
    11. frame8.ScrollRectItemsAdapter.Util.GridView.GridAdapter`2:ChangeItemsCount(ItemCountChangeMode, Int32, Int32, Boolean, Boolean) (at Assets/SRIA/Scripts/Util/GridView/GridAdapter.cs:62)
    12. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ResetItems(Int32, Boolean, Boolean) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIA.cs:163)
    13. GalleryGridScrollView:OnEnable() (at Assets/Scripts/GalleryGridScrollView.cs:43)
    14. UnityEngine.EventSystems.EventSystem:Update()
    15.  
    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.AbstractViewsHolder.Init (UnityEngine.GameObject rootPrefabGO, Int32 itemIndex, Boolean activateRootGameObject, Boolean callCollectViews) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/AbstractViewsHolder.cs:32)
    3. frame8.ScrollRectItemsAdapter.Util.GridView.CellGroupViewsHolder`1[GridViewsHolder].Init (UnityEngine.GameObject groupPrefab, Int32 itemIndex, UnityEngine.RectTransform cellPrefab, Int32 numCellsPerGroup) (at Assets/SRIA/Scripts/Util/GridView/CellGroupViewsHolder.cs:82)
    4. frame8.ScrollRectItemsAdapter.Util.GridView.GridAdapter`2[TParams,TCellVH].CreateViewsHolder (Int32 itemIndex) (at Assets/SRIA/Scripts/Util/GridView/GridAdapter.cs:163)
    5. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2[TParams,TItemViewsHolder].ComputeVisibility (Double abstractDelta) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:1080)
    6. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2[TParams,TItemViewsHolder].ComputeVisibilityForCurrentPosition (Boolean forceFireScrollViewPositionChangedEvent, Boolean virtualizeContentPositionIfNeeded, Boolean alsoCorrectTransversalPositions) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:434)
    7. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2[TParams,TItemViewsHolder].ComputeVisibilityForCurrentPosition (Boolean forceFireScrollViewPositionChangedEvent, Boolean virtualizeContentPositionIfNeeded, Boolean alsoCorrectTransversalPositions, Double overrideScrollingDelta) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:413)
    8. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2[TParams,TItemViewsHolder].ChangeItemsCountInternal (ItemCountChangeMode changeMode, Int32 count, Int32 indexIfInsertingOrRemoving, Boolean contentPanelEndEdgeStationary, Boolean keepVelocity) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:315)
    9. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2[TParams,TItemViewsHolder].ChangeItemsCount (ItemCountChangeMode changeMode, Int32 itemsCount, Int32 indexIfInsertingOrRemoving, Boolean contentPanelEndEdgeStationary, Boolean keepVelocity) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIA.cs:175)
    10. frame8.ScrollRectItemsAdapter.Util.GridView.GridAdapter`2[TParams,TCellVH].ChangeItemsCount (ItemCountChangeMode changeMode, Int32 cellsCount, Int32 indexIfAppendingOrRemoving, Boolean contentPanelEndEdgeStationary, Boolean keepVelocity) (at Assets/SRIA/Scripts/Util/GridView/GridAdapter.cs:62)
    11. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2[TParams,TItemViewsHolder].ResetItems (Int32 itemsCount, Boolean contentPanelEndEdgeStationary, Boolean keepVelocity) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIA.cs:163)
    12. GalleryGridScrollView.OnEnable () (at Assets/Scripts/GalleryGridScrollView.cs:43)
    13. UnityEngine.EventSystems.EventSystem:Update()
    14.  


    Thank you again for the support.
    Felipe.
     
  47. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Hi Felipe. Thanks!

    R1: I suggest you to take a look at the MultiplePrefabs example - you can use the same code structure as there, only that your prefab is for cells and you'll have a base views holder for the cell, from which you create derived classes for your custom views holders. The GridAdapter has method callbacks for cells which correspond to the usual ones, like CreateCellViewsHolder() instead of CreateViewsHolder(), so make sure to use them instead. Also, try to strip everything you think it's non-essential from the multiple prefabs example scripts, so you can focus on the core parts and see the whole picture faster. Come back with another post or through email if after this things still aren't 100% clear.

    R2: First, thanks for posting both the code and the error - this is the perfect way of reporting a potential issue <3
    Tip: never assign a static "instance" variable without immediately setting it to null in OnDestroy() - will save you a lot of headaches (maybe this was sufficient enough to give you errors?).
    Let's see, you have 2 errors. The second one is most probably because the "root" doesn't have a RectTransform component (how?). The first one most probably causes it, because it skips adding this component (it a very weird way - maybe it has something to do with that static instance?).
    I tried doing the same thing to the original grid example, and there are no errors.
    a) try setting the instance to null in OnDestroy and tell me if this alone solves it.
    b) If a) is not enough to fix it, at GridParams:56, change the line
    Code (CSharp):
    1. var go = new GameObject(scrollRect.name + "_GridAdapter_GroupPrefab");
    to
    Code (CSharp):
    1. var go = new GameObject(scrollRect.name + "_GridAdapter_GroupPrefab", typeof(RectTransform));
    I am curious about this issue too, so let me know what you find

    Lucian
     
    KeiseEntertainment likes this.
  48. KeiseEntertainment

    KeiseEntertainment

    Joined:
    May 5, 2015
    Posts:
    23
    Hi there,

    R1: I'll try that later on. But for now i think its all clear. Thanks. =]

    R2: Actually the static "instance" variable is not being used at all, so i deleted it (but thanks for the tip, i'll change all my codes to reflect that). I made 2 tests, one without the static variable (got exactly the same error) and the other test was changing the code you mentioned. With the code change i got 3 errors now (new code and erros bellow).

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4. using TMPro;
    5. using CodeStage.AntiCheat.ObscuredTypes;
    6. using frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter;
    7. using frame8.ScrollRectItemsAdapter.Util.GridView;
    8. using System;
    9. using frame8.Logic.Misc.Other.Extensions;
    10.  
    11. /// <summary>Minimal implementation of the adapter that initializes & updates the viewholders. The size of each item is fixed in this case and it's the same as the prefab's</summary>
    12. public class GalleryGridScrollView : GridAdapter<GridParams, GridViewsHolder>
    13. {
    14.     private bool isInitialized = false;
    15.  
    16.     #region GridAdapter implementation
    17.     /// <inheritdoc/>
    18.     protected override void Awake()
    19.     {
    20.         base.Awake();
    21.     }
    22.  
    23.     /// <inheritdoc/>
    24.     protected override void Start()
    25.     {
    26.         base.Start();
    27.  
    28.         isInitialized = true;
    29.         ResetItems(PlayerDataManager.instance.models.Count);
    30.     }
    31.  
    32.     private void OnEnable()
    33.     {
    34.         //Verifica se o script já foi inicializado.
    35.         if (!isInitialized)
    36.             return;
    37.  
    38.         Debug.Log("GalleryGridScrollView.OnEnable()");
    39.         ResetItems(PlayerDataManager.instance.models.Count);
    40.  
    41.         ////Verifica possui algum modelo salvo a ser carregado. Pular a inicialização caso seja 0 para evitar bugs.
    42.         //if (PlayerDataManager.instance.models.Count > 0)
    43.         //{
    44.         //    Debug.Log("PlayerDataManager.instance.models.Count > 0");
    45.         //    //Verifica se o script já foi inicializado.
    46.         //    if (!isInitialized)
    47.         //    {
    48.         //        Debug.Log("!isInitialized");
    49.         //        base.Awake();
    50.         //        base.Start();
    51.         //        isInitialized = true;
    52.         //    }
    53.  
    54.         //    ResetItems(PlayerDataManager.instance.models.Count);
    55.         //}
    56.     }
    57.  
    58.     /// <summary> Called when a cell becomes visible </summary>
    59.     /// <param name="viewsHolder"> use viewsHolder.ItemIndexto find your corresponding model and feed data into its views</param>
    60.     protected override void UpdateCellViewsHolder(GridViewsHolder newOrRecycled)
    61.     {
    62.         //newOrRecycled.button.onClick.RemoveAllListeners();
    63.         //newOrRecycled.button.onClick.AddListener(() => { TopScrollView.instance.SelectCategory(newOrRecycled.ItemIndex); });
    64.  
    65.         ModelSettings modelSettings = PlayerDataManager.instance.models[newOrRecycled.ItemIndex];
    66.         newOrRecycled.background.sprite = Resources.Load<Sprite>(string.Format("Sprites/Backgrounds/Backgrounds/{0}", modelSettings.background));
    67.  
    68.         switch (modelSettings.model)
    69.         {
    70.             case GameManager.Models.PUMPKIN:
    71.                 newOrRecycled.pumpkinModel.SetModelSettings(modelSettings.modelData);
    72.                 break;
    73.         }
    74.     }
    75.     #endregion
    76. }
    77.  
    78. // Self-explanatory
    79. public class GridViewsHolder : CellViewsHolder
    80. {
    81.     public Button button;
    82.     public Image background;
    83.  
    84.     public PumpkinModel pumpkinModel;
    85.  
    86.     public override void CollectViews()
    87.     {
    88.         base.CollectViews();
    89.  
    90.         button = views.GetComponent<Button>();
    91.         views.GetComponentAtPath("Background", out background);
    92.         views.GetComponentAtPath("PumpkinModel", out pumpkinModel);
    93.     }
    94.     protected override RectTransform GetViews() { return root.Find("Views") as RectTransform; }
    95. }
    96.  

    Code (CSharp):
    1. Can't add a 'RectTransform' to the "GalleryGridScrollView_GridAdapter_GroupPrefab" game object during Awake when a 'Transform' is already attached.
    2. You probably need to add a 'RectTransform' to the "GalleryGridScrollView_GridAdapter_GroupPrefab" game object in the editor.
    3. UnityEngine.GameObject:.ctor(String, Type[])
    4. frame8.ScrollRectItemsAdapter.Util.GridView.GridParams:GetGroupPrefab(Int32) (at Assets/SRIA/Scripts/Util/GridView/GridParams.cs:56)
    5. frame8.ScrollRectItemsAdapter.Util.GridView.GridAdapter`2:CreateViewsHolder(Int32) (at Assets/SRIA/Scripts/Util/GridView/GridAdapter.cs:163)
    6. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ComputeVisibility(Double) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:1080)
    7. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ComputeVisibilityForCurrentPosition(Boolean, Boolean, Boolean) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:434)
    8. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ComputeVisibilityForCurrentPosition(Boolean, Boolean, Boolean, Double) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:413)
    9. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ChangeItemsCountInternal(ItemCountChangeMode, Int32, Int32, Boolean, Boolean) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:315)
    10. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ChangeItemsCount(ItemCountChangeMode, Int32, Int32, Boolean, Boolean) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIA.cs:175)
    11. frame8.ScrollRectItemsAdapter.Util.GridView.GridAdapter`2:ChangeItemsCount(ItemCountChangeMode, Int32, Int32, Boolean, Boolean) (at Assets/SRIA/Scripts/Util/GridView/GridAdapter.cs:62)
    12. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ResetItems(Int32, Boolean, Boolean) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIA.cs:163)
    13. GalleryGridScrollView:OnEnable() (at Assets/Scripts/GalleryGridScrollView.cs:39)
    14. UnityEngine.EventSystems.EventSystem:Update()
    15.  
    Code (CSharp):
    1. Can't add a 'RectTransform' to the "GalleryGridScrollView_GridAdapter_GroupPrefab" game object during Awake when a 'Transform' is already attached.
    2. You probably need to add a 'RectTransform' to the "GalleryGridScrollView_GridAdapter_GroupPrefab" game object in the editor.
    3. UnityEngine.GameObject:AddComponent()
    4. frame8.ScrollRectItemsAdapter.Util.GridView.GridParams:GetGroupPrefab(Int32) (at Assets/SRIA/Scripts/Util/GridView/GridParams.cs:65)
    5. frame8.ScrollRectItemsAdapter.Util.GridView.GridAdapter`2:CreateViewsHolder(Int32) (at Assets/SRIA/Scripts/Util/GridView/GridAdapter.cs:163)
    6. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ComputeVisibility(Double) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:1080)
    7. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ComputeVisibilityForCurrentPosition(Boolean, Boolean, Boolean) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:434)
    8. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ComputeVisibilityForCurrentPosition(Boolean, Boolean, Boolean, Double) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:413)
    9. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ChangeItemsCountInternal(ItemCountChangeMode, Int32, Int32, Boolean, Boolean) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:315)
    10. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ChangeItemsCount(ItemCountChangeMode, Int32, Int32, Boolean, Boolean) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIA.cs:175)
    11. frame8.ScrollRectItemsAdapter.Util.GridView.GridAdapter`2:ChangeItemsCount(ItemCountChangeMode, Int32, Int32, Boolean, Boolean) (at Assets/SRIA/Scripts/Util/GridView/GridAdapter.cs:62)
    12. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2:ResetItems(Int32, Boolean, Boolean) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIA.cs:163)
    13. GalleryGridScrollView:OnEnable() (at Assets/Scripts/GalleryGridScrollView.cs:39)
    14. UnityEngine.EventSystems.EventSystem:Update()
    15.  
    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.AbstractViewsHolder.Init (UnityEngine.GameObject rootPrefabGO, Int32 itemIndex, Boolean activateRootGameObject, Boolean callCollectViews) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/AbstractViewsHolder.cs:32)
    3. frame8.ScrollRectItemsAdapter.Util.GridView.CellGroupViewsHolder`1[GridViewsHolder].Init (UnityEngine.GameObject groupPrefab, Int32 itemIndex, UnityEngine.RectTransform cellPrefab, Int32 numCellsPerGroup) (at Assets/SRIA/Scripts/Util/GridView/CellGroupViewsHolder.cs:82)
    4. frame8.ScrollRectItemsAdapter.Util.GridView.GridAdapter`2[TParams,TCellVH].CreateViewsHolder (Int32 itemIndex) (at Assets/SRIA/Scripts/Util/GridView/GridAdapter.cs:163)
    5. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2[TParams,TItemViewsHolder].ComputeVisibility (Double abstractDelta) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:1080)
    6. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2[TParams,TItemViewsHolder].ComputeVisibilityForCurrentPosition (Boolean forceFireScrollViewPositionChangedEvent, Boolean virtualizeContentPositionIfNeeded, Boolean alsoCorrectTransversalPositions) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:434)
    7. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2[TParams,TItemViewsHolder].ComputeVisibilityForCurrentPosition (Boolean forceFireScrollViewPositionChangedEvent, Boolean virtualizeContentPositionIfNeeded, Boolean alsoCorrectTransversalPositions, Double overrideScrollingDelta) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:413)
    8. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2[TParams,TItemViewsHolder].ChangeItemsCountInternal (ItemCountChangeMode changeMode, Int32 count, Int32 indexIfInsertingOrRemoving, Boolean contentPanelEndEdgeStationary, Boolean keepVelocity) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIAInternal.cs:315)
    9. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2[TParams,TItemViewsHolder].ChangeItemsCount (ItemCountChangeMode changeMode, Int32 itemsCount, Int32 indexIfInsertingOrRemoving, Boolean contentPanelEndEdgeStationary, Boolean keepVelocity) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIA.cs:175)
    10. frame8.ScrollRectItemsAdapter.Util.GridView.GridAdapter`2[TParams,TCellVH].ChangeItemsCount (ItemCountChangeMode changeMode, Int32 cellsCount, Int32 indexIfAppendingOrRemoving, Boolean contentPanelEndEdgeStationary, Boolean keepVelocity) (at Assets/SRIA/Scripts/Util/GridView/GridAdapter.cs:62)
    11. frame8.Logic.Misc.Visual.UI.ScrollRectItemsAdapter.SRIA`2[TParams,TItemViewsHolder].ResetItems (Int32 itemsCount, Boolean contentPanelEndEdgeStationary, Boolean keepVelocity) (at Assets/SRIA/Scripts/DLLSources/ScrollRectItemsAdapter/SRIA.cs:163)
    12. GalleryGridScrollView.OnEnable () (at Assets/Scripts/GalleryGridScrollView.cs:39)
    13. UnityEngine.EventSystems.EventSystem:Update()
    14.  

    Thank you!
    Felipe
     
  49. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Then ignore the code that adds the RectTransform, bc it's clear that it's added automatically, as expected.
    It complains about creating the gameobject at runtime and immediately adding a RT component (which should be allowed). For a quick fix, add a 'groupPrefab' field to the GridParams class and use that instead of 'new GameObject()'. Create an empty UI game object in editor with a vertical\horizontal layout group component(if the scrollview is horizontal\vertical. Yes, the opposite.), and assign it to that field.
    This would be a quick fix, but I'd reallylike to know what causes the issue as I tried several things on the grid example demo and I can't get any error.
    I'd really appreciate it if you could send me the project (or at least the relevant parts, but runnable) via email to further investigate it.

    Also, if even the fix I gave you now doesn't work, I need to see the project. :)
     
    KeiseEntertainment likes this.
  50. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    846
    Found it!
    This is a unity bug on some versions: Unity Issue Tracker - Error when creating a RectTransform component in an Awake call of an instantiated MonoBehaviour

    Here's the actual hotfix I've just included in the official release (will be live in a few days, most probably):

    In GridParams class, add this method at the end:
    Code (CSharp):
    1.  
    2.         protected void CreateCellGroupPrefab()
    3.         {
    4.             var go = new GameObject(scrollRect.name + "_CellGroupPrefab", typeof(RectTransform));
    5.  
    6.             // Additional reminder of the "add recttransform in awake" bug explained in InitIfNeeded()
    7.             if (!(go.transform is RectTransform))
    8.                 Debug.LogException(new UnityException("SRIA: Don't call SRIA.Init() outside MonoBehaviour.Start()!"));
    9.  
    10.             go.SetActive(false);
    11.             go.transform.SetParent(scrollRect.transform, false);
    12.             if (scrollRect.horizontal)
    13.                 _TheOnlyGroupPrefab = go.AddComponent<VerticalLayoutGroup>(); // groups are columns in a horizontal scrollview
    14.             else
    15.                 _TheOnlyGroupPrefab = go.AddComponent<HorizontalLayoutGroup>(); // groups are rows in a vertical scrollview
    16.             _TheOnlyGroupPrefab.spacing = contentSpacing;
    17.             _TheOnlyGroupPrefab.childForceExpandWidth = cellWidthForceExpandInGroup;
    18.             _TheOnlyGroupPrefab.childForceExpandHeight = cellHeightForceExpandInGroup;
    19.             _TheOnlyGroupPrefab.childAlignment = alignmentOfCellsInGroup;
    20.             _TheOnlyGroupPrefab.padding = groupPadding;
    21.         }
    22.  
    In GridParams.InitIfNeeded(ISRIA), append this code:
    Code (CSharp):
    1.  
    2.             // Hotfix 12.10.2017 14:45: There's a bug in Unity on some versions: creating a new GameObject at runtime and adding it a RectTransform cannot be done in Awake() or OnEnabled().
    3.             // See: https://issuetracker.unity3d.com/issues/error-when-creating-a-recttransform-component-in-an-awake-call-of-an-instantiated-monobehaviour
    4.             // The bug was initially found in a project where the initial count is 0 (when Start() is called), then the scrollview is disabled, set a non-zero count, then enabled back,
    5.             // and in OnEnable() the user called ResetItems(), which triggered the lazy-instantiation of the group prefab - since it's created in the first GetGroupPrefab() call.
    6.             // Solved it by creating the prefab here, because InitIfNeeded(ISRIA) is called at Init time (in MonoBehaviour.Start())
    7.             CreateCellGroupPrefab();
    8.  
    In GridParams.GetGroupPrefab(int), replace everything with this code:
    Code (CSharp):
    1.  
    2.             if (_TheOnlyGroupPrefab == null)
    3.                 throw new UnityException("GridParams.InitIfNeeded() was not called by SRIA. Did you forget to call base.Start() in <YourAdapter>.Start()?");
    4.  
    5.             return _TheOnlyGroupPrefab;
    6.  
    .. and, if you also care about the updated summary of the SRIA.Init() method:
    Code (CSharp):
    1.  
    2.         /// <summary>
    3.         /// <para>Initialize the adapter. This is automatically called in Start(), but it may also be called manually, if for some reason you implement Start() and don't want to call base.Start()</para>
    4.         /// <para>Will call Canvas.ForceUpdateCanvases(), Params.InitIfNeeded(), will initialize the internal state and will change the items count to 0</para>
    5.         /// <para>IMPORTANT: Do not call it in Awake(), OnEnable(), OnDisable(). OnStart() is the best place to do it.</para>
    6.         /// </summary>
    7.  

    Also look at SRIA.Initialized property, which becomes true after Init was caleld - maybe you don't need to create your own "initialized" flag
     
    KeiseEntertainment likes this.