Scenario:
I've created an overlay window (with tag = 100) that I eventually want to dismiss. But the following code doesn't work:
UIApplication.shared.windows.first?.becomeKey()
UIApplication.shared.windows.last?.resignKey()
(lldb) po UIApplication.shared.windows
▿ 2 elements
- 0 : <UIWindow: 0x7fa698d0ad00; frame = (0 0; 768 1024); gestureRecognizers = <NSArray: 0x600000048550>; layer = <UIWindowLayer: 0x6000000278a0>>
- 1 : <UIWindow: 0x7fa698d14bb0; frame = (0 0; 768 1024); autoresize = W+H; tag = 100; gestureRecognizers = <NSArray: 0x600000252a50>; layer = <UIWindowLayer: 0x600000229660>>
Any ideas to either toggle or delete the overlay window?
Simply set the window's isHidden property to true:
var overlayWindow: UIWindow?
...
overlayWindow?.isHidden = true
overlayWindow = nil // optional
If you set any references to this window to nil, the window will be disposed.
Please also note that you are not supposed to call resignKey(). From its documentation (emphasis mine):
Discussion
Never call this method directly. The system calls this
method and posts UIWindowDidResignKey to let the window know when it
is no longer key. The default implementation of this method does
nothing, but subclasses can override it and use it to perform tasks
related to resigning the key window status.
The same is true for becomeKey(), by the way. You probably want to use makeKey() or makeKeyAndVisible().
This is essentially a two-part question.
How do I display a created UIWindow and
How do I dismiss it?
I learned that I have to keep a reference to the newly-created UIWindow rather than merely have local-scope reference. ...which is obvious.
Once I have a persistent reference to the ancillary UIWindow, I can merely assign nil to it to remove it:
var hamburgerWindow:UIWindow?
#IBAction func displayOverlayWindowAction() {
guard hamburgerWindow != nil else {
displayOverLay()
return
}
hamburgerWindow = nil
}
Related
I have this calendar I'm working on in jetpack compose. I have gotten some help with placement in rows and stuff like that using weight. The problem is though that I'm trying to make an item of a month in the calendar and place that in a LazyRow but i think it has to do with that lazy rows are scrollable so the weight function for the box with the text in it makes it so that no text shows up if the code looks like this...
fun CalendarRowItem(calendarSize: Int, initWeekday: Int, textColor: Color, clickedColor: Color){
var dayCounter: Int = 1
var week: Int = 1
var _initWeekday = initWeekday
Column() {
while(dayCounter <= calendarSize){
Row(modifier = Modifier.fillMaxWidth().padding(5.dp)) {
if(initWeekday > 0){
repeat(initWeekday){
Spacer(modifier = Modifier.weight(1f))
}
}
for (i in week..(7 - _initWeekday)){
if(dayCounter <= 31){
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.padding(10.dp)
.background(clickedColor, CircleShape)
.clickable { }
) {
Text(text = dayCounter++.toString(), color = textColor )
}
}else{
Spacer(modifier = Modifier.weight(1f))
}
_initWeekday = 0
}
}
}
}
}
but without the weight i cant place the dates correctly plus i have no clue how i would make it so that only one item is visible in the screen at once?
I think using HorizontalPager instead of LazyRow may suit better in this case: it has pagination, as you probably don't need your scroll to stop in between the month, and won't have such a problem out of the box, as same modifier as I suggest you below in applied by the component.
Below is a general answer to the problem, as you still may face it in other cases.
That indeed happens because the parent is horizontally scrollable.
In such case Modifier.fillMaxWidth, as well as Modifier.weight with fill parameter set to true (it's default value) has no effect, as parent width constraint is equal to infinity.
You need to restrict parent width. In this case Modifier.fillParentMaxWidth() can be used on the container: it'll make the view width be equal to the LazyRow width - the part of scroll view which takes exactly "one screen".
As this modifier is defined on LazyItemScope, you have two options to apply it:
Define CalendarRowItem on the scope, in this case CalendarRowItem will only be available to use from lazy view item.
fun LazyItemScope.CalendarRowItem(/* ... */) {
// ...
Column(Modifier.fillParentMaxWidth()) {
// ...
}
}
Add a modifier parameter for CalendarRowItem and pass Modifier.fillParentMaxWidth from item scope:
fun CalendarRowItem(/* ... */, modifier: Modifier) {
// ...
Column(modifier) {
// ...
}
}
items(yourItems) { item ->
CalendarRowItem(
/* ... */,
modifier = Modifier.fillParentMaxWidth()
)
}
Ok, I have looked EVERYWHERE and am trying here to simply extract an animation from a .dae imported into Xcode (or a .scn, whatever) so that I can run it on the model throughout my scene kit game. the problem is every way to do this that is referenced (including here Scenekit: Add animation to SCNNode from external Collada)
seems to be deprecated in iOS 11. So I have no way to animate any 3D model I put in my scene.
Right now I am able to display the model just still with this - I get the model from my dae and put it into my blank scn :
if let d = modelScene.rootNode.childNodes.first
{
theDude.node = d
theDude.setupNode() //this scales it down
}
func setupNode()
{
node.scale = SCNVector3(x: modifier, y: modifier, z: modifier)
}
//Then add to scene on tap
let clone = theDude.node.clone()
theDude.node = clone
self.sceneView.scene.rootNode.addChildNode(theDude.node)
theDude.node.position = hitPosition
This works. Trying to get it to run the animation that I added to it in Maya, however, does not. I added these extensions per Apple's example to my project:
https://developer.apple.com/library/content/samplecode/Fox/Listings/Swift_Common_SceneKitExtensions_swift.html
And was trying to do this as it says to, just with a cube as a basic test (from the above question):
func addAnim()
{
let characterScene = SCNScene(named: "art.scnassets/cubeAnimatedSkeleton.dae")!
let characterTopLevelNode = characterScene.rootNode.childNodes[0]
sceneView.scene.rootNode.addChildNode(characterTopLevelNode)
let idleAnimation = CAAnimation.animationWithSceneNamed("art.scnassets/cubeAnimatedSkeleton.dae")!
idleAnimation.usesSceneTimeBase = false
idleAnimation.repeatCount = Float.infinity
characterTopLevelNode.addAnimation(idleAnimation, forKey: "idle")
}
But with this CAAnimation.animationWithSceneNamed("art.scnassets/cubeAnimatedSkeleton.dae")! the whole thing does not work because this extension from APPLE:
extension CAAnimation {
class func animationWithSceneNamed(_ name: String) -> CAAnimation? {
var animation: CAAnimation?
if let scene = SCNScene(named: name) {
scene.rootNode.enumerateChildNodes({ (child, stop) in
if child.animationKeys.count > 0 {
animation = child.animation(forKey: child.animationKeys.first!) //ERROR
stop.initialize(to: true)
}
})
}
return animation
}
}
says that addAnimation for key was deprecated in iOS 11. Replacing that with animation = child.animationPlayer(forKey: child.animationKeys.first!) doesn't work, and I don't know what else to do.
What is wrong here?
I have a custom control which needs to do some things when loading at run time, based on a published property. However, I am running into a problem where, whenever I check the published property, it has not been set yet, and is always the default value.
I first attempted checking the property in the constructor, of the control, but quickly found they were not loaded yet. I know that when the control is shown on the screen the properties are set correctly, thus its not an issue with the properties not being loaded at all.
I next attempted overriding the Loaded Method but am still having the same problem, so I don't think this is exactly what I am looking for.
void __fastcall TFmSearchBar::Loaded()
{
TEdit::Loaded(); //call base class loaded
if( MyProperty )
{
//do stuff
}
}
At what point are these published properties actually getting set?
What method can/should I hook into in order to execute some logic in my control based on these properties, as soon as the properties are set correctly?
If I check the property in the constructor of the control, the property is always the default value even if I have specified otherwise in the designer.
Correct, because its design-time values have not been assigned yet.
At what point are these published properties actually getting set?
When the Owner (Form, Frame, or DataModule) is being constructed. It loads its own DFM resource and parses it, constructing stored child components and reading their property values.
For example, say you have the following DFM:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
...
object Edit1: TEdit
Left = 136
Top = 64
Width = 121
Height = 21
TabOrder = 0
end
object Button1: TButton
Left = 263
Top = 62
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 1
end
end
The DFM streaming process roughly translates to the following equivalent code (I'm leaving a lot of internal details out for simplicity):
__fastcall TCustomForm::TCustomForm(TComponent *Owner)
: TScrollingWinControl(Owner)
{
this->FFormState << fsCreating;
try
{
// locate, load, and parse the "Form1" DFM resource ...
this->FComponentState << csLoading;
this->Parent = ...;
this->Name = L"Form1":
this->FComponentState << csReading;
this->Left = 0;
this->Top = 0;
this->Caption = L"Form1";
...
TEdit *e = new TEdit(this);
try
{
e->FComponentState << csLoading;
e->Parent = this;
e->Name = L"Edit1"; // <-- sets the derived Form's 'Edit1' member to this object
e->FComponentState << csReading;
e->Left = 136;
e->Top = 64;
e->Width = 121;
e->Height = 21;
e->TabOrder = 0;
e->FComponentState >> csReading;
}
catch (...)
{
delete e;
throw;
}
TButton *b = new TButton(this);
try
{
b->FComponentState << csLoading;
b->Parent = this;
b->Name = L"Button1"; // <-- sets the derived Form's 'Button1' member to this object
b->FComponentState << csReading;
b->Left = 263;
b->Top = 62;
b->Width = 75;
b->Height = 25;
b->Caption = L"Button1";
b->TabOrder = 1;
b->FComponentState >> csReading;
}
catch (...)
{
delete b;
throw;
}
this->FComponentState >> csReading;
...
e->Loaded();
b->Loaded();
this->Loaded();
}
__finally
{
this->FFormState >> fsCreating;
}
}
So, as you can see, a component's property values are not available yet when its constructor is called.
What method can/should I hook into in order to execute some logic in my control based on these properties, as soon as the properties are set correctly?
That depends on what the properties need to do. If they need to perform operations immediately, you can do that directly in their property setters. But if they need to wait until other properties have been loaded first (if one property is dependent on the value of another property), then override the virtual Loaded() method instead, which is automatically called after DFM streaming is finished. Property setters can check the flags of the ComponentState property to know whether or not the component is currently running in the Form Designer at design-time, whether or not a DFM is currently being streamed, etc and then act accordingly as needed.
I attempted overriding the Loaded Method but am still having the same problem
Which is what exactly? You did not explain what your actual problem is. Please edit your question to provide those details.
so I don't think this is exactly what I am looking for.
It most likely is, you probably are just not using it correctly.
I'd like to know more about how this system works, specifically when and how the framework actually decides to update a UI element.
My application has a 'tools' system where a single tool can be active at a time. I used the "ON_UPDATE_COMMAND_UI" message to 'check' the tool's icon/button in the UI, which affected both the application menu and the toolbars. Anyway, this was all working great until some point in the last couple of days, when the toolbar icons stopped getting highlighted properly.
I investigated a little and found that the update command was only being received when the icon was actually clicked. What's strange is this is only affecting the toolbars, not the menu, which is still working fine. Even when the buttons in the menu are updated the toolbar icon stays the same.
Obviously I've done something to break it - any ideas?
EDIT:
Never mind. I'd overwritten the Application's OnIdle() method and hadn't called the original base class method - that is, CWinApp::OnIdle() - which I guess is where the update gets called most of the time. This code snippet from https://msdn.microsoft.com/en-us/library/3e077sxt.aspx illustrates:
BOOL CMyApp::OnIdle(LONG lCount)
{
// CWinApp's original method is involved in the update message handling!
// Removing this call will break things
BOOL bMore = CWinApp::OnIdle(lCount);
if (lCount == 0)
{
TRACE(_T("App idle for short period of time\n"));
bMore = TRUE;
}
// ... do work
return bMore;
// return TRUE as long as there are any more idle tasks
}
Here's a good article that kinda explains how to do it. Don't use his code example with WM_KICKIDLE though, instead scroll down to the comments section. There are two code samples that explain how to do it better. I quote:
//Override WM_INITMENUPOPUP
void CDialog::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
CDialog::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
// TODO: Add your message handler code here
if(pPopupMenu &&
!bSysMenu)
{
CCmdUI CmdUI;
CmdUI.m_nIndexMax = pPopupMenu->GetMenuItemCount();
for(UINT i = 0; i < CmdUI.m_nIndexMax; i++)
{
CmdUI.m_nIndex = i;
CmdUI.m_nID = pPopupMenu->GetMenuItemID(i);
CmdUI.m_pMenu = pPopupMenu;
// There are two options:
// Option 1. All handlers are in dialog
CmdUI.DoUpdate(this, FALSE);
// Option 2. There are handlers in dialog and controls
/*
CmdUI.DoUpdate( this, FALSE );
// If dialog handler doesn't change state route update
// request to child controls. The last DoUpdate will
// disable menu item with no handler
if( FALSE == CmdUI.m_bEnableChanged )
CmdUI.DoUpdate( m_pControl_1, FALSE );
...
if( FALSE == CmdUI.m_bEnableChanged )
CmdUI.DoUpdate( m_pControl_Last, TRUE );
*/
}
}
}
See if this helps - http://msdn.microsoft.com/en-us/library/essk9ab2(v=vs.80).aspx
I am developing a custom print dialog and page setup using MFC and VS2008 for my Win32 program. Since the code is legacy, I can't take much advantage from MFC view/doc architecture. As a result, I wrote a printing code completely from scratch.
I setup CPrintInfo, instantiate my custom print dialog box and hook this dialog box to the CPrintInfo I just created. When my custom print dialog is up, I have a radio button to let a user toggles the page orientation. For some reasons, I couldn't modify the current DEVMODE at the run-time. As a result, every page I print will end up as a portrait.
Even if I manually set pDevMode->dmOrientation to DMORIENT_LANDSCAPE from the event handler of the custom print dialog, the printing result is still ended up as portrait. I am really not sure why this is happening and how to modify the DevMode after the print dialog is up.
Thank you in advance for any help.
Here is the code I have:
void PrintSomething(CWnd* currentWnd) {
// Create CPrintInfo
CPrintInfo* pPrintInfo = new CPrintInfo;
SetupPrintInfo(pPrintInfo); // simply setup some member variables of CPrintInfo
// Create a custom print dialog
CustomPrintDlg* pCustomPrtDlg = new CustomPrintDlg(FALSE, PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS
| PD_HIDEPRINTTOFILE | PD_NOSELECTION, pPrintInfo, currentWnd);
SetupPrintDialog(pPrintInfo,pCustomPrtDlg);
if ( AfxGetApp()->DoPrintDialog(pCustomPrtDlg) == IDOK ) {
... // proceed a print loop
}
}
Code for setting up the custom print dialog:
void SetupPrintDialog(CPrintInfo* pPrintInfo,CustomPrintDlg* pCustomPrtDlg) {
delete pInfo->m_pPD;
pInfo->m_pPD = pCustomPrtDlg;
pInfo->m_pPD->m_pd.hInstance = AfxGetInstanceHandle();
pInfo->m_pPD->m_pd.lpPrintTemplateName = MAKEINTRESOURCE(IDD_CUSTOM_PRTDLG);
// Set the Flags of the PRINTDLG structure as shown, else the
// changes will have no effect.
pInfo>m_pPD->m_pd.Flags |= PD_ENABLEPRINTTEMPLATE;
// Set the page range.
pInfo>m_pPD->m_pd.nMinPage = 1; // one based page numbers.
pInfo>m_pPD->m_pd.nMaxPage = 0xffff; // how many pages is unknown.
}
When a user toggles the radio button to Landscape, this function will be invoked:
void CustomPrintDlg::OnLandscapeChecked() {
// set the current Devmode to landscape
LPDEVMODE pDevMode = GetDevMode();
GlobalUnlock(pDevMode);
pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
}
A pseucode for the custom print dialog class:
class CustomPrintDlg: public CPrintDialog {
... // just override some methods from CPrintDialog
};
Thanks again,
Unagi
I figured out the solution:
All I need is to call GlobalLock to obtain a pointer to the Devmode before changing the current DevMode.
void CustomPrintDlg::OnLandscapeChecked()
{
// set the current Devmode to landscape
LPDEVMODE pDevMode = GetDevMode();
GlobalLock(pDevMode);
pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
GlobalUnlock(pDevMode)
}
Thanks again for helping me.
Nowhere in your example code do you show how you're creating the DC for printing. When you call CreateDC, you must pass a pointer to a DEVMODE structure; this defines whether the printing will be portrait or landscape.