Titanium JIRA Archive
Appcelerator Community (AC)

[AC-312] Android only : ListView ignores formatting some cases, iOS works fine

GitHub Issuen/a
TypeBug
Priorityn/a
StatusResolved
ResolutionNeeds more info
Resolution Date2015-11-29T08:51:51.000+0000
Affected Version/sn/a
Fix Version/sn/a
Componentsn/a
LabelsListItem, ListView
ReporterHenry David Spells III
AssigneeSharif AbuDarda
Created2015-08-21T15:45:07.000+0000
Updated2015-11-30T01:27:45.000+0000

Description

Alloy.Globals.SliderDrawer =
{
	ListFontSize: 16,
	LineHeight : 34,
	Center: { y: 17 },
	Width: 180,
	TextColor: 'white',
	BackgroundColor: 'transparent',
	BackgroundGradient: {
        type: 'linear',
        startPoint: { x: '100%', y: '50%' },
        endPoint: { x: '0%', y: '50%' },
        colors: [ { color: '#464646', offset: 0.0}, { color: '#343434', offset: 0.33 }, { color: '#2E2E2E', offset: 0.67 }, { color: '#383838', offset: 1.0 } ],
	}
};

function doMenuButton(e)
{
	Ti.API.info('doMenuButton(' + JSON.stringify(e) + ')');
	var controller = Alloy.createController('sliderdrawer');
  	controller.initialize(Alloy.Globals.menuItems,
  		{
  			top: isIOS ? 20 : 0,
  			right: 0,
  			width: Alloy.Globals.SliderDrawer.Width,
  			backgroundGradient: Alloy.Globals.SliderDrawer.BackgroundGradient
  		},
  		{
  			right: 0,
  			width: Alloy.Globals.SliderDrawer.Width,
  			separatorColor: '#802E2E2E'
  		},
  		Alloy.Globals.SliderDrawer.Width, handleMenuEvent);
}

Alloy.Globals.SliderDrawer.ChatMenuItem = { template: 'withBadge', eventname: 'socialComments', iconTop: {text: '\uf086'}, option: {text: 'Chat'}, badge: {text: 0} };

function AddToSlideDrawerMenu(item)
{
	putIfAbsent(item, 'template', 'noBottom');
	putIfAbsent(item, 'properties', {});
	putIfAbsent(item.properties, 'height', Alloy.Globals.SliderDrawer.LineHeight);
	putIfAbsent(item.properties, 'backgroundColor', Alloy.Globals.SliderDrawer.BackgroundColor);
	if ('option' in item)
		putIfAbsent(item.option, 'color', Alloy.Globals.SliderDrawer.TextColor);
	if ('iconTop' in item)
		putIfAbsent(item.iconTop, 'color', Alloy.Globals.SliderDrawer.TextColor);
	if ('iconBottom' in item)
		putIfAbsent(item.iconBottom, 'color', Alloy.Globals.SliderDrawer.TextColor);
	Alloy.Globals.menuItems.push(item);
}

	Alloy.Globals.menuItems = [];
	AddToSlideDrawerMenu({ eventname: 'scheduleTab', iconTop: {text: '\uf073'}, option: {text: 'Schedule'} });
	AddToSlideDrawerMenu({ eventname: 'benchmarkTab', iconTop: {text: '\uf012'}, option: {text: 'Tracking'} });
	AddToSlideDrawerMenu(Alloy.Globals.SliderDrawer.ChatMenuItem);
	AddToSlideDrawerMenu({ eventname: 'profileTab', iconTop: {text: '\uf007'}, option: {text: 'Profile'} });
	AddToSlideDrawerMenu({ template: 'template', eventname: 'goalsTab', iconBottom: {text: '\uf05b'}, iconTop: {text: '\uf140'}, option: {text: 'My Next Goal'} });
	AddToSlideDrawerMenu({ eventname: 'injuryTab', iconTop: {text: '\uf0fa'}, option: {text: 'Injuries?'} });
	AddToSlideDrawerMenu({ eventname: 'splashpage', iconTop: {text: '\uf0a1'}, option: {text: 'Announcements'} });
	AddToSlideDrawerMenu({ eventname: 'signOut', iconTop: {text: '\uf08b'}, option: {text: 'Sign out'} });

Attachments

FileDateSize
image001.png2015-08-21T15:34:31.000+0000114179
screenshot-2015-08-21_09.58.01.928.png2015-08-21T15:32:55.000+0000163972
sliderdrawer.js2015-08-21T15:37:11.000+00003073
sliderdrawer.tss2015-08-21T15:37:04.000+00002194
sliderdrawer.xml2015-08-21T15:36:56.000+00001254

Comments

  1. Fokke Zandbergen 2015-08-24

    [~dspells] please strip out any code from your example that does not relate to the bug. Make it as minimalistic as you can. Also, please use proper JIRA formatting, include the iOS and Android versions you use and the steps you take to get the bug and what you expect to get instead. The easier the engineers can reproduce it the sooner they can fix it.
  2. Henry David Spells III 2015-08-24

    I have stripped out all the code except for the code that brings up the menu that shows up on the far right? There is no extraneous code. I only included the code for the menu window and the code to call the menu window. All the code relates to the bug (i.e. the window that contains the menu and the code to bring up the window). You should be able to use the following steps (approximately) 1) Create a new Mobile App Project 2) Add the sliderdraw.js, sliderdraw.tss, slider draw.xml files to your project 3) Make sure that your index.js, index.xml, index.tss file have an open window in it (Any simple sample project should do). You may find it helpful to have a label or a button in the window but it should be optional. 4) Copy and paste the code in the description section into your index.js file 5) Call the doMenuButton function in some way (adding a button to the window that you call from and using the doMenuButton as the handler is one way of doing that but just calling doMenuButton({}); with an open window should work also I am using iOS 8.4 SDK and the code works properly on every emulator that I've tried includes the iPhone 4s, iPhone 6 and iPad 2 emulators. I am using Genymotion emulators and every emulator I have tried fails including 3 standard emulators that come with Genymotion 1) "Google Nexus 5 - 5.1.0 - API 22 - 1080x1920" and 2) Samsung Galaxy S4 - 4.4.4 - API 19 - 1080x1920 and 3) Custom Phone - 5.0.0 - API 21 - 768x1280. When I package the code I'm using the "Android 5.1.1 [armeabi-v7a]" SDK Results: On iOS the window comes up and the icons / views are placed correctly according to the positions specified in the sliderdraw.tss file. On android the windows come up and icons / view come up "somewhat" centered. The iconTopId and optionId buttons are placed relative to each other appropriately but centered overall even though the left edge is specified as 0 and 40 respectively. The badge button is centered also even though it is clearly specified that it's right edge should be 5. Expected results: On an android device the left edge of the views specified by #iconTopId should start at 0 units from the left edge of the list view On an android device the left edge of the views specified by #optionId should start at 40 units from the left edge of the list view On an android device the right edge of the views that use the "badgeViewClass" should have their right edge 5 units from the right edge of the list view Two photos were already included that showed the "Results" on both platforms. It was already specified that the iOS picture was the "Expected Results" and that the Android picture contained "Unexpected Results". Hopefully the wording above will provide more context. It should be easiest to reproduce if I don't try to rip out random parts of the code for the menu. I apologize for not telling you to call the doMenuButton function. The rest of the steps should be obvious to any engineer who has used appcelerator for more than a month. I tried to make sure that all the constants were in one place and initialized properly so it would be easy to add to a project. Hopefully I did that correctly. Why do you think that some code is unnecessary? If so why do you think so? Did you actually try to add the code to a project or just automatically throw the bug back?
  3. Fokke Zandbergen 2015-08-24

    What I mean is have you tried to isolate the issue? Can you reproduce this by simply creating a ListView, add styling to align labels left and then see it still rendered centre on Android? I'm not the one triaging these tickets to decide what to do with it - just want to help you to improve the chance of getting it resolved.
  4. Henry David Spells III 2015-08-24

    There are many list views in my application. I don't have any of them acting like this one and I have no idea why. I can show you very similar code in my popup view control that works correctly. Something in the API layer is making a different choice and I don't know why. I've worked in the software industry for 27 years including 24 years at Adobe. In my 24 years at Adobe, we never asked our customers to do so much work to find bugs in our software as you guys do. It's just that many days I feel like I'm doing your work for you. Maybe I just screwed somewhere on this list view, but it's so similar to all the other list views and I've compared every line of .tss, xml and .js that I can think of trying to see something different and I just don't see it. I'll do my best to start stripping it down. And you add new bugs / changes that break my program or compelling almost every major update over the past 2 years.
  5. Fokke Zandbergen 2015-08-25

    With your experience I'm sure you know it's not a small thing to try to account for thousands of API changes in 3 different platforms every year and that every once in a while breaking changes in iOS/Android will mean breaking changes in Titanium as well. You will also I'm sure understand that a well formatted (your code is not), clearly described (which was missing in the initial ticket), easy to reproduce (no steps were included) bug is more likely to get attention. I'm not asking you to fix the bug, just want to help you to get a fix (if needed) to you asap.
  6. Henry David Spells III 2015-08-25

    I see what you mean about being well formatted. My code is perfectly formatted on my computer but I keep forgetting how to make it well formatted in JIRA. Thanks for helping me understand what you meant there. Thanks for fixing the formatting. When you said "Proper JIRA formatting" and then talked about "Results" and "Expected Results" I got the two confused.
  7. Henry David Spells III 2015-10-01

    I would really appreciate it if someone would at least spend a little time looking into this problem. This UI is supposed to be the center of my navigation for my app ongoing. It looks great on iOS and terrible on Android. Any help/advice would be appreciated. I examined the properties carefully for more than a solid day in this code and it looks almost identical to code that works well in my app. Ideas on what I could try? Anything? It's been over a month now since I have submitted this bug.
  8. Henry David Spells III 2015-10-01

    I found a workaround by wrapping every list item in another view. I'm not sure why this is necessary for Android but not iOS.
       <Alloy>
       	<Window id="PopupControl" class="container" onOpen="doOnOpen" onClick="doClose" androidback="doClose" onClose="doOnClose" backgroundColor="transparent">
       		<View id="backgroundView">
       	        <ListView id="listView" defaultItemTemplate="noBottom">
       	
       	            <Templates>
       	                <ItemTemplate id="template" name="template">
       	                	<View class="fullWidthContainerClass" layout="composite">
       		                    <Label bindId="iconBottom" id="iconBottomId" />
       		                    <Label bindId="iconTop" id="iconTopId" />
       		                    <Label bindId="option" id="optionId" />
       	                	</View>
       	                </ItemTemplate>
       	                <ItemTemplate id="noBottom" name="noBottom">
       	                	<View class="fullWidthContainerClass" layout="composite">
       		                    <Label bindId="iconTop" id="iconTopId" />
       		                    <Label bindId="option" id="optionId" />
       	                	</View>
       	                </ItemTemplate>
       	                <ItemTemplate id="profileId" name="profile">
       	                	<View class="fullWidthContainerClass" layout="composite">
       		                	<View bindId="imageContainer" id="imageContainerId" >
       		                    	<ImageView bindId="image" id="imageId" image="" />
       		                    </View>
       		                    <Label bindId="iconTop" id="iconTopId" class="profileIconClass" />
       		                    <Label bindId="option" id="optionId" class="profileOptionClass" />
       		                    <Label bindId="name" id="nameId" class="profileNameClass" />
       	                	</View>
       	                </ItemTemplate>
       	                <ItemTemplate id="withBadge" name="withBadge">
       	                	<View class="fullWidthContainerClass" layout="composite">
       							<View id="badgeView" class="badgeViewClass">
       								<Label bindId="badge" class="badgeTextClass" />
       							</View>
       		                    <Label bindId="iconTop" id="iconTopId" />
       		                    <Label bindId="option" id="optionId" />
       	                	</View>
       	                </ItemTemplate>
       	            </Templates>
       	
       	            <ListSection id="optionsSection">
       	            </ListSection>
       	        </ListView>
       		</View>
       	</Window>
       </Alloy>
       
       '.fullWidthContainerClass': {
       	width: Ti.UI.FILL,
       	height: Ti.UI.SIZE
       },
       
  9. Sharif AbuDarda 2015-11-22

    Hello [~dspells], I tried to test the issue with the original test code. I followed the steps to regenerate the issue. I got an error "putIfAbsent" is undefined in "AddToSlideDrawerMenu(item)". What am I doing wrong? thanks.
  10. Henry David Spells III 2015-11-22

        // put in a key / value pair if the key is not already overridden by the caller
        function putIfAbsent(item, key, value)
        {
        	if (!(key in item))
        		item[key] = value;
        	else
        		value = item[key];
        	return value;
        }
        
        
        
  11. Sharif AbuDarda 2015-11-29

    Hello [~dspells], I tried to test the issue with your original test code. I followed your instruction as 1) Created a new Mobile App Project 2) Add the sliderdraw.js, sliderdraw.tss, sliderdraw.xml files to my project. 3) In index.js, index.xml, index.tss file I have an open window in it. I have a label in the window. 4) Copy and paste this code in the index.js file
        Alloy.Globals.SliderDrawer =
        
        {
        
            ListFontSize: 16,
        
            LineHeight : 34,
        
            Center: { y: 17 },
        
            Width: 180,
        
            TextColor: 'white',
        
            BackgroundColor: 'transparent',
        
            BackgroundGradient: {
        
                type: 'linear',
        
                startPoint: { x: '100%', y: '50%' },
        
                endPoint: { x: '0%', y: '50%' },
        
                colors: [ { color: '#464646', offset: 0.0}, { color: '#343434', offset: 0.33 }, { color: '#2E2E2E', offset: 0.67 }, { color: '#383838', offset: 1.0 } ],
        
            }
        
        };
        
        
        function putIfAbsent(item, key, value)
        
        {
        
            if (!(key in item))
        
                item[key] = value;
        
            else
        
                value = item[key];
        
            return value;
        
        }
        
         
        
        function doMenuButton(e)
        
        {
        
            Ti.API.info('doMenuButton(' + JSON.stringify(e) + ')');
        
            var controller = Alloy.createController('sliderdrawer');
        
            controller.initialize(Alloy.Globals.menuItems,
        
                {
        
                    top: isIOS ? 20 : 0,
        
                    right: 0,
        
                    width: Alloy.Globals.SliderDrawer.Width,
        
                    backgroundGradient: Alloy.Globals.SliderDrawer.BackgroundGradient
        
                },
        
                {
        
                    right: 0,
        
                    width: Alloy.Globals.SliderDrawer.Width,
        
                    separatorColor: '#802E2E2E'
        
                },
        
                Alloy.Globals.SliderDrawer.Width, handleMenuEvent);
        
        }
        
         
        
        Alloy.Globals.SliderDrawer.ChatMenuItem = { template: 'withBadge', eventname: 'socialComments', iconTop: {text: '\uf086'}, option: {text: 'Chat'}, badge: {text: 0} };
        
         
        
        function AddToSlideDrawerMenu(item)
        
        {
        
            putIfAbsent(item, 'template', 'noBottom');
        
            putIfAbsent(item, 'properties', {});
        
            putIfAbsent(item.properties, 'height', Alloy.Globals.SliderDrawer.LineHeight);
        
            putIfAbsent(item.properties, 'backgroundColor', Alloy.Globals.SliderDrawer.BackgroundColor);
        
            if ('option' in item)
        
                putIfAbsent(item.option, 'color', Alloy.Globals.SliderDrawer.TextColor);
        
            if ('iconTop' in item)
        
                putIfAbsent(item.iconTop, 'color', Alloy.Globals.SliderDrawer.TextColor);
        
            if ('iconBottom' in item)
        
                putIfAbsent(item.iconBottom, 'color', Alloy.Globals.SliderDrawer.TextColor);
        
            Alloy.Globals.menuItems.push(item);
        
        }
        
         
        
            Alloy.Globals.menuItems = [];
        
            AddToSlideDrawerMenu({ eventname: 'scheduleTab', iconTop: {text: '\uf073'}, option: {text: 'Schedule'} });
        
            AddToSlideDrawerMenu({ eventname: 'benchmarkTab', iconTop: {text: '\uf012'}, option: {text: 'Tracking'} });
        
            AddToSlideDrawerMenu(Alloy.Globals.SliderDrawer.ChatMenuItem);
        
            AddToSlideDrawerMenu({ eventname: 'profileTab', iconTop: {text: '\uf007'}, option: {text: 'Profile'} });
        
            AddToSlideDrawerMenu({ template: 'template', eventname: 'goalsTab', iconBottom: {text: '\uf05b'}, iconTop: {text: '\uf140'}, option: {text: 'My Next Goal'} });
        
            if (boxprefs.prefs.ONOFF_MEDALERT)
        
                AddToSlideDrawerMenu({ eventname: 'injuryTab', iconTop: {text: '\uf0fa'}, option: {text: 'Injuries?'} });
        
            if (boxprefs.prefs.SPLASHPAGEANNOUNCEMENT != "")
        
                AddToSlideDrawerMenu({ eventname: 'splashpage', iconTop: {text: '\uf0a1'}, option: {text: 'Announcements'} });
        
            AddToSlideDrawerMenu({ eventname: 'signOut', iconTop: {text: '\uf08b'}, option: {text: 'Sign out'} });
        
        
        
        
        $.index.open();
        
    5) Called the "doMenuButton" function by label event listener. Now I am having the error, "Uncaught ReferenceError: boxprefs is not defined". Please provide a clear sample code for me to test the validity of the bug. Thanks.
  12. Henry David Spells III 2015-11-30

    I apologize for not totally cleaning up the sample code. I removed the lines with boxprefs. They are not relevant to the test case.

JSON Source