Skip to content

Instantly share code, notes, and snippets.

@Raztor0
Last active March 22, 2016 04:53
Show Gist options
  • Save Raztor0/fee5778a35e52f9b922a to your computer and use it in GitHub Desktop.
Save Raztor0/fee5778a35e52f9b922a to your computer and use it in GitHub Desktop.
import xml.etree.ElementTree as ET
import xml.dom.minidom as minidom
import sys
import uuid
def main(argv):
xibPath = ''
tree = ''
attemptFixup = False
try:
xibPath = argv[0]
if(len(argv) == 2):
attemptFixup = argv[1] == '--attempt-fixup'
tree = ET.parse(xibPath)
except Exception, e:
print e
sys.exit(2)
# Returns a string of the format xxx-xx-xxx
def getUUID():
myid = str(uuid.uuid4()).strip('-')
myid = myid[:8]
myid = myid[:3] + '-' + myid[3:5] + '-' + myid[5:8]
return myid
'''
copy and paste from http://effbot.org/zone/element-lib.htm#prettyprint
it walks your tree and adds spaces and newlines so the tree is
printed in a nice way
'''
def indent(elem, level=0):
i = "\n" + level*" "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
indent(elem, level+1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
# Grab some relevant elements
document = tree.getroot()
objects = document.find("objects")
superview = objects.find("view")
superviewframe = superview.find('rect')
superviewId = superview.attrib['id']
subviews = superview.find("subviews")
constraints = superview.find("constraints")
if superview == None or subviews == None:
print 'Cannot scrollify a xib with no views'
sys.exit(2)
# Keep track of the constraints currently linked to the superview
constraintsToConvert = constraints.findall(".//constraint[@secondItem='" + superviewId+ "']")
for constraint in constraints:
# Some constraints which point to the superview don't specify a 'firstItem' attribute
if constraint.get('firstItem') == None and constraint.get('secondItem') in (o.get('id') for o in subviews):
constraintsToConvert.append(constraint)
for constraint in constraintsToConvert:
constraints.remove(constraint)
# Keep track of the bottom-most subview for later
currentBottom = 0
bottomMostView = subviews[0]
for view in subviews.findall(".//rect[@key='frame']/.."):
rect = view.find("rect")
bottom = float(rect.attrib['y']) + float(rect.attrib['height'])
if bottom >= currentBottom:
currentBottom = bottom
bottomMostView = view
# Create the scrollview
scrollviewId = getUUID()
scrollview = ET.Element('scrollView', {'clipsSubviews': 'YES', 'contentMode': 'scaleToFill', 'id' : scrollviewId, 'multipleTouchEnabled': 'YES', 'translatesAutoresizingMaskIntoConstraints': 'NO'})
scrollview.insert(0, superviewframe)
# Add a constraints section on the scrollview
scrollviewConstraints = ET.Element('constraints')
scrollview.append(scrollviewConstraints)
# Add a subviews section on the scrollview
scrollviewSubviews = ET.Element('subviews')
scrollview.append(scrollviewSubviews)
# Add scrollview constraints to superview
for constraintAttribute in ['leading', 'trailing', 'top', 'bottom']:
scrollviewConstraint = ET.Element('constraint', {'firstItem': scrollviewId, 'firstAttribute': constraintAttribute, 'secondItem': superviewId, 'secondAttribute': constraintAttribute, 'id': getUUID()})
constraints.insert(0, scrollviewConstraint)
# Create the container view
containerViewId = getUUID()
containerview = ET.Element('view', {'contentMode': 'scaleToFill', 'translatesAutoresizingMaskIntoConstraints': 'NO', 'id': containerViewId})
# Add it to the scrollview's subviews
scrollviewSubviews.insert(1, containerview)
# Give it a background colour
bgColour = ET.Element('color', {'key': 'backgroundColor', 'white': '1', 'alpha': '1', 'colorSpace': 'calibratedWhite'})
containerview.insert(0, bgColour)
# And a frame
containerFrame = ET.Element('rect', {'key': 'frame', 'x': '0', 'y': '0', 'width': superviewframe.attrib['width'], 'height': str(currentBottom)})
containerview.insert(1, containerFrame)
# And its own subviews section
containerSubviews = ET.Element('subviews')
containerview.insert(2, containerSubviews)
# And its own constraints section
containerConstraints = ET.Element('constraints')
containerview.insert(3, containerConstraints)
# Move the original subviews to the container
for view in subviews:
containerSubviews.append(view)
# Clear the old subviews
subviews.clear()
# Update the original subview constraints to point to our container
for constraint in constraintsToConvert:
if constraint.get('firstItem') != None:
constraint.set('secondItem', containerViewId)
containerConstraints.append(constraint)
# Add width constraint for our container
widthConstraint = ET.Element('constraint', {'firstItem': containerViewId, 'firstAttribute': 'width', 'secondItem': superviewId, 'secondAttribute': 'width', 'id': getUUID()})
constraints.append(widthConstraint)
# Set the container constraints on the scrollview
for constraintAttribute in ['leading', 'trailing', 'top', 'bottom']:
containerConstraint = ET.Element('constraint', {'firstItem': containerViewId, 'firstAttribute': constraintAttribute, 'secondItem': scrollviewId, 'secondAttribute': constraintAttribute, 'id': getUUID()})
scrollviewConstraints.insert(0, containerConstraint)
if attemptFixup:
# Constrain the bottom of the container to the bottom-most item in our hierarchy
bottomConstraint = ET.Element('constraint', {'firstItem': containerViewId, 'firstAttribute': 'bottom', 'secondItem': bottomMostView.get('id'), 'secondAttribute': 'bottom', 'id': getUUID()})
containerConstraints.append(bottomConstraint)
# Finally add the scrollview to the hierarchy
subviews.insert(0, scrollview)
indent(document)
tree.write(xibPath, xml_declaration=True, encoding='utf-8', method="xml")
if __name__ == "__main__":
main(sys.argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment