Need Support for Apple Pencil/Finger drawing on Swift 3 - swift3

I am making use of swift 2.3 with TouchCanvas (Apple Pencil Sample App),
in which while drawing,
I am able to switch between pen/pencil/brush/eraser - thickness & colors and the same is applied correspondingly.
Ref:
Now I upgraded to swift 3.0,
in which which drawing,
when switch between pen/pencil/brush/eraser - thickness & colors, the last picked one is applied to ALL.
Ref:
and also tried apple latest pencil API..Results were same
can please any one tell me exact solution for this..

Ahhhh...After trying long hours ...found an solution..
Just one line on CanvasView.swift
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()!
context.setLineCap(.round)
needsFullRedraw = false //Added this line
if (needsFullRedraw) {
setFrozenImageNeedsUpdate()
frozenContext.clear(bounds)
for array in [finishedLines,lines] {
for line in array {
line.drawCommitedPointsInContext(frozenContext, isDebuggingEnabled: isDebuggingEnabled, usePreciseLocation: usePreciseLocations)
}
}
needsFullRedraw = false
}
frozenImage = frozenImage ?? frozenContext.makeImage()
if let frozenImage = frozenImage {
context.draw(frozenImage, in: bounds)
}
for line in lines {
line.drawInContext(context, isDebuggingEnabled: isDebuggingEnabled, usePreciseLocation: usePreciseLocations)
}
}
or just commented the following line
/*if (needsFullRedraw) {
setFrozenImageNeedsUpdate()
frozenContext.clear(bounds)
for array in [finishedLines,lines] {
for line in array {
line.drawCommitedPointsInContext(frozenContext, isDebuggingEnabled: isDebuggingEnabled, usePreciseLocation: usePreciseLocations)
}
}
needsFullRedraw = false
}*/

Related

GetColor from GradientDrawable in kotlin

I've programmatically set a GradientDrawable background up like so, and am trying to test for it's color. The main issue seems to be getting the color from the shape (GradientDrawable) at test time.
This snippet is from within a larger binding adapter..
color = ContextCompat.getColor(
textView.context, R.color.ColorRatingHigh
)
val shape = GradientDrawable()
shape.shape = GradientDrawable.OVAL
shape.setColor(color)
shape.setStroke(2, Color.BLACK)
textView.setBackground(shape)
The test is set up like so..
#Test
fun MovieDetailRatingColorTest() {
...
onView(withId(R.id.movie_vote_average))
.check(matches(withBackgroundColor(R.color.ColorRatingHigh)))
}
...
fun withBackgroundColor(expectedColor: Int): Matcher<View?>? {
Checks.checkNotNull(expectedColor)
return object : BoundedMatcher<View?, TextView>(TextView::class.java) {
override fun matchesSafely(textView: TextView): Boolean {
val actualColor = (textView.getBackground() as ColorDrawable).color
return expectedColor == actualColor
}
override fun describeTo(description: Description) {
description.appendText("with background color: ")
}
}
}
unfortunately I'm getting the following ClassCastException
android.graphics.drawable.GradientDrawable cannot be cast to android.graphics.drawable.ColorDrawable
I've seen a few post on the site regarding similar issues to this,
but none seem to be working and most end up with the same issues.. eg Testing background color espresso Android
or have answers which seem outdated or suffer from java to kotlin conversion.. eg how to get the color from GradientDrawable
came up with a workaround, using the fragment scenario to get access to 'ContextCompat'.
This allowed me to retrieve the 'R.color' directory.
getColor retrieves the 2's complement of the colorId that was originally being passed in... which happens to match the id retrieved here:
val actualColor = (textView.getBackground() as ColorDrawable).color.defaultColor
lateinit var scenario: FragmentScenario<MovieDetailFragment>
...
#Test
fun MovieDetailRatingColorTest() {
var expectedColor: Int? = 0
scenario.onFragment { fragment ->
expectedColor =
fragment.context?.let {
ContextCompat.getColor(it, R.color.ColorRatingHigh )
}
}
onView(withId(R.id.movie_vote_average))
.check(matches(withBackgroundColor(expectedColor)))
}
then I editted the withBackground() function to match the new input
fun withBackgroundColor(expectedColor: Int?): Matcher<View?>? {
Checks.checkNotNull(expectedColor)
return object : BoundedMatcher<View?, TextView>(TextView::class.java) {
override fun matchesSafely(textView: TextView): Boolean {
val actualColor = (textView.getBackground() as GradientDrawable).color?.defaultColor
return expectedColor == actualColor
}
override fun describeTo(description: Description) {
description.appendText("with background color: $expectedColor")
}
}
}

Swift 3 load .dae file into SCNNode

Loading a .dae file as a scene element
This code works, loading the file as the scene:
let scene = SCNScene(named: "art.scnassets/base-wall-tile_sample.dae")!
This code, loading the file as SCNGeometry, doesn't:
let url = Bundle.main.url(forResource: "art.scnassets/base-wall-tile_sample", withExtension: "dae")
let source = SCNSceneSource(url: url! )
let geo = source!.entryWithIdentifier("Geo", withClass: SCNGeometry.self)!
url and source are ok, but it crashes trying to produce geo. Bad instruction.
This code, like several examples offered on the web, was in Swift 2 (load a collada (dae) file into SCNNode (Swift - SceneKit). I had to juggle it to Swift 3, and something seems to have been lost in translation. Can someone tell me how to do this stuff right?
A .dae file is always loaded as a SCNScene. You need to name the node containing the geometry you want to add.
Than you can load the scene, filter it for the node with the given name and add it to your scene.
func addNode(named nodeName, fromSceneNamed: sceneName, to scene: SCNScene) {
if let loadedScene = SCNScene(named: sceneName),
let node = loadedScene.rootNode.childNode(withName: nodeName, recursivly: true) {
scene.rootNode.addChildNode(node)
}
}
guard let shipScene = SCNScene(named: "ship.dae") else { return }
let shipNode = SCNNode()
let shipSceneChildNodes = shipScene.rootNode.childNodes
for childNode in shipSceneChildNodes {
shipNode.addChildNode(childNode)
}
node.addChildNode(shipNode)

Swift 2 to 3 conversion error with Value of type '[Any]' has no member

I'm having a problem with a Swift 2 to 3 conversion piece of work and some of the remains syntax giving: Value of type '[Any]' has no member errors.
I was hoping someone could point me at a good solution.
Swift 2 code
Swift 2 code
func search() {
epsonPrinters = [Printer]()
starPrinters = [Printer]()
epson_startSearching()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { [unowned self] in
let devices = SMPort.searchPrinter()
self.starPrinters = devices.map { portInfo -> Printer in
let p = Printer(
id: portInfo.modelName,
make: "Star Micronics",
model: portInfo.modelName,
portName: portInfo.portName)
if let name = portInfo.modelName as? String {
p.emulation = name.containsString("TSP143") ? "StarGraphics" : "StarLine"
}
return p
}
}
}
Swift 3 Code (I've added comments above areas with errors)
func search() {
epsonPrinters = [Printer]()
starPrinters = [Printer]()
epson_startSearching()
DispatchQueue.global(qos: .background).async { [unowned self] in
let devices = SMPort.searchPrinter()
self.starPrinters = [devices.map { portInfo -> Printer in
// id, model and portName in below fails with messages like:
// Value of type '[Any]' has no member 'modelName'
let p = Printer(
id: portInfo.modelName,
make: "Star Micronics",
model: portInfo.modelName,
portName: portInfo.portName)
// error on portInfo.modelName
// Value of type '[Any]' has no member 'modelName'
if let name = portInfo.modelName as? String {
p.emulation = name.containsString("TSP143") ? "StarGraphics" : "StarLine"
}
return p
}!]
}
}
I know that I can replace the 'id:...' part with the likes of:
id: ((portInfo[0] as AnyObject).modelName) ?? "",
But this isn't correct because PortInfo can have none, 1 or multiples depending on the number of printers we find.
I'd appreciate any suggestions for refactoring this in an elegant way that is good Swift 3 syntax and likely to survive into Swift 4.
I'm working in Xcode 8.3.2
When you get some errors about types, you'd better check what type each variable has. When you select devices in the line let devices = ..., Quick Help of Xcode will show you something like this:
Declaration let devices: [Any]?
First, it's an Optional and you need to unwrap it, before using the actual content.
Second, the type of the elements in devices is Any, to which you cannot apply any methods (including property accessors). You need to cast it to an appropriate type at an appropriate place.
To solve the two things above, you can write something like this:
guard let devices = SMPort.searchPrinter() as? [PortInfo] else {
fatalError("This may never happen")
}
With guard statement above, Quick Help will show you:
Declaration let devices: [PortInfo]
Non-Optional, simple Array of PortInfo, so you can use any methods of PortInfo for the elements of this devices.
I would translate your Swift 2 code into Swift 3 like this:
func search() {
epsonPrinters = []
starPrinters = []
epson_startSearching()
DispatchQueue.global(qos: .default).async {
guard let devices = SMPort.searchPrinter() as? [PortInfo] else {
fatalError("This may never happen")
}
self.starPrinters = devices.map { portInfo -> Printer in
let p = Printer(
id: portInfo.modelName,
make: "Star Micronics",
model: portInfo.modelName,
portName: portInfo.portName)
if let name = portInfo.modelName {
p.emulation = name.contains("TSP143") ? "StarGraphics" : "StarLine"
}
return p
}
}
}
You may need some fixes (not many, I believe) to use this code, as you are not showing all relevant things such as the definition of Printer.

selecting attitude reference frame in IOS 10 coremotion using swift 3

I am trying to use CMMotionManager to update the attitude of a camera viewpoint in scenekit. I am able to get the following code using the default reference to work.
manager.deviceMotionUpdateInterval = 0.01
manager.startDeviceMotionUpdates(to: motionQueue, withHandler:{ deviceManager, error in
if (deviceManager?.attitude) != nil {
let rotation = deviceManager?.attitude.quaternion
OperationQueue.main.addOperation {
self.cameraNode.rotation = SCNVector4(rotation!.x,rotation!.y,rotation!.z,rotation!.w)
}
}
})
I am however unable to get startDeviceMotionUpdates to work with a selected reference frame as shown below:
manager.deviceMotionUpdateInterval = 0.01
manager.startDeviceMotionUpdates(using: CMAttitudeReferenceFrameXMagneticNorthZVertical, to: motionQueue, withHandler:{ deviceManager, error in
if (deviceManager?.attitude) != nil {
let rotation = deviceManager?.attitude.quaternion
OperationQueue.main.addOperation {
self.cameraNode.rotation = SCNVector4(rotation!.x,rotation!.y,rotation!.z,rotation!.w)
}
}
})
The error i receive is:
Use of unresolved identifier 'CMAttitudeReferenceFrameXMagneticNorthZVertical'
I get similar error messages for other reference frames as well. Can anyone shed any light on the use of the "using:" parameter for the startDeviceMotionUpdates function? All the examples i have found are for older versions of swift or objective c so it is quite possible that it is simply an issue with not understanding Swift 3 syntax.
After some additional fiddling i figured out that the using argument expects a member of the new CMAttitudeReferenceFrame struct. i.e. it should be passed as:
manager.deviceMotionUpdateInterval = 0.01
manager.startDeviceMotionUpdates(using: CMAttitudeReferenceFrame.xMagneticNorthZVertical
,to: motionQueue, withHandler:{
deviceManager, error in
if (deviceManager?.attitude) != nil {
let rotation = deviceManager?.attitude.quaternion
OperationQueue.main.addOperation {
self.cameraNode.rotation = SCNVector4(rotation!.x,rotation!.y,rotation!.z,rotation!.w)
}
}
})
This is a change from earlier version that allowed the direct use of constants such as "CMAttitudeReferenceFrameXMagneticNorthZVertical"

Flex: Spark List's Indeces in View change on Orientation Change

I have a spark list with a variable row_height (2 custom itemRenderer: Header 30 px, Contact 60 px) that on the only first orientation change after a scroll, change the indexes in view.
I tried to set Header to be 60 px height, and i had no problems with the orientation change.
I'm not setting the verticalScrollPosition anywhere. Adding an event listener on the viewport's list and watching the verticalScrollPosition, it doesn't change on orientation change.
I really don't know how can i fix that.
EDIT:
This is the code relative to the list:
<fx:Script>
protected function creationCompleteHandler(event:FlexEvent):void
{
addressBookViewModel = ViewModelFactory.getInstance().getAddressBookViewModel();
addressBookViewModel.getUserContacts(onDataReceived);
}
protected function pagedContactsList_initializeHandler(event:FlexEvent):void
{
asyncListView.list = pagedContactsList;
}
private function onDataReceived():void
{
pagedContactsList.length = (BusinessContext.getInstance().getTotalContacts() + BusinessContext.getInstance().getTotalLastNames());
loadPagedData();
}
private function createPendingItemFunctionHandler(index:int, ipe:ItemPendingError):Object
{
if(!addressBookViewModel.pageUp)
{
addressBookViewModel.pageUp = true;
addressBookViewModel.currentPage++;
addressBookViewModel.getMoreUserContacts(onMoreDataRecieved, onMoreDataMissing);
}
return loadingDataHeader;
}
private function onMoreDataRecieved():void
{
loadPagedData();
}
private function loadPagedData():void
{
for(var i:int = 0; i < addressBookViewModel.contacts.length; i++)
{
pagedContactsList.setItemAt(addressBookViewModel.contacts.getItemAt(i), pagedContactsList.lastItemInsertedIndex);
pagedContactsList.lastItemInsertedIndex++;
}
addressBookViewModel.pageUp = false;
}
internal var headerItemRender:ClassFactory = new ClassFactory(HeaderItemRenderer);
internal var contactItemRenderer:ClassFactory = new ClassFactory(ContactItemRenderer);
private function rendererFunction(item:Object):ClassFactory
{
return item.hasOwnProperty("isHeader") ? headerItemRender : contactItemRenderer;
}
</fx:Script>
<fx:Declarations>
<custom:PagedArrayList id="pagedContactsList" initialize="pagedContactsList_initializeHandler(event)"/>
</fx:Declarations>
<s:List id="list" width="100%"
height="100%" itemRendererFunction="rendererFunction" change="list1_changeHandler(event)">
<s:AsyncListView id="asyncListView" createPendingItemFunction="createPendingItemFunctionHandler" />
</s:List>
The curious thing is that before and after the orientation change the list.scroller.viewport.verticalScrollPosition has the same value even if the list has scrolled ~ 40 rows. (40 is the page size).
I have many lists in my app, and every list that has const row_height has no issue, but the 2 with a variable row_height have this problem. Maybe it's caused by the AsyncListView.
EDIT 2:
I removed the AsyncListView, binding directly addressBookViewModel.contacts to the list.dataProvider, removing the pagination and the issue is still there.
EDIT 3:
I think that the only thing to do is to put breakpoints everywhere in the Scroller's class.
EDIT 4:
This issue happens only when scrolling to the bottom of the list.
EDIT 5:
Find the issue!
VerticalLayout.as, in updateDisplayListVirtual(row 1797) there's a call to a method (updateLLV) that set up a LinearLayoutVector using a typicalLayoutElement. This is lazily init with the first itemRenderer added to the dataGroup of the list. In my case it's the HeaderItemRenderer (30px).
After the updateLLV, the startIndex (index of the first visible item) is setted by calling the indexOf on the LinearLayoutVector and passing the verticalScrollPosition. (briefly: verticalScrollPosition / typicalLayoutElement.height)
The problem is that nowhere is taken into consideration the variableRowHeight!
Workaround found! Not so elegant, but it works.
stage.eventListener(StageOrientationEvent.ORIENTATION_CHANGING, yourReorientHandler, false, 1)
Setting the priority is really important, otherwise the updateDisplayListVirtual will be called before your handler.
private function reorientHandler(event:StageOrientationEvent):void
{
var IndecesInView:Vector.<int> = list.dataGroup.getItemIndicesInView();
var firstInView:int = IndecesInView[0];
callLater(
function():void
{
if(!list.layout.getScrollPositionDeltaToElement(firstInView+1)) return;
list.scroller.viewport.verticalScrollPosition += list.layout.getScrollPositionDeltaToElement(firstInView+1).y;
});
}