Calling setTitleTextAttributes on UIBarButtonItem does not have any impact on iOS 11 - ios11

I am using an appearance proxy in didFinishLaunchingWithOptions to set UIBarButtonItem title font across the project like this:
UIBarButtonItem.appearance().setTitleTextAttributes([
NSAttributedStringKey.font: customFont
]
, for: .normal)
What I would like to do is to change this font based on user choice?
So upon the user choosing a font I store it in UserDefaults and I send a local notification to those view controllers I know have UIBarButtonItems and I reset each directly like this:
navigationItem.leftBarButtonItems?.forEach { $0.setTitleTextAttributes([NSAttributedStringKey.font: ...], for: .normal) }
navigationItem.rightBarButtonItems?.forEach { $0.setTitleTextAttributes([NSAttributedStringKey.font: ...], for: .normal) }
navigationItem.backBarButtonItem?.setTitleTextAttributes([NSAttributedStringKey.font: customFont], for: .normal)
This works as expected in iOS 10 but in iOS 11 it doesn't have an immediate impact on either left, right or back bar button items.
The back bar button item gets adjusted to the new font if a view controller is popped and then pushed again to the navigation stack - the bar button items don't change until the next app run.
I am naturally doing the same thing with navigation bar title so in the AppDelegate:
UINavigationBar.appearance().titleTextAttributes = [
NSAttributedStringKey.font: ...
]
if #available(iOS 11.0, *) {
UINavigationBar.appearance().largeTitleTextAttributes = [
NSAttributedStringKey.font : ...
]
}
And in each view controller I reset these values again and titles instantly change font.
I tried to set bar button items title text attributes to the new font in each control state, namely: [.normal, .highlighted, .disabled] with no luck.
I also tried to set navigationItem.leftBarButtonItem to a new instance of UIBarButonItem hoping this will have the new font but the button disappears completely :D
Last thing I tried was to call setNeedsDisplay and layoutIfNeeded on the navigation bar but still nothing happens.
A sample project of the case could be found here

Here's a super hacky mechanism to work around what appears to be an obvious bug (or undocumented optimization):
for controlState in [UIControlState.disabled, .highlighted, .normal] {
self.changeBarButtonFont(barButtonItem: self.updateButton, font: font, controlState: controlState)
self.changeBarButtonFont(barButtonItem: self.selectButton, font: font, controlState: controlState)
}
private func changeBarButtonFont(barButtonItem: UIBarButtonItem, font: UIFont, controlState: UIControlState) {
barButtonItem.title = barButtonItem.title! + " "
barButtonItem.setTitleTextAttributes([NSAttributedStringKey.font : font], for: controlState)
DispatchQueue.main.async
{
barButtonItem.title = barButtonItem.title?.trimmingCharacters(in: CharacterSet.whitespaces)
}
}
Note that this does not work 100% as rapid taps on the 'Change font' won't register. But perhaps you could work this out?

Related

Dynamic Icons in Flutter

I retrieve some data from my DB, where I have a Column called "icon" in which I stored some Strings. For each of them, I want to pass in the Icon class of Flutter, charging the corresponding Icon.
I have the single String inside
items[index]["icon"]
But I can't pass it inside Icon(items[index]["icon"])
How can I do?
You can use the icons directly with their literal names by accessing the Material Icons font directly with Text() widget.
Example:
Text(
'perm_contact_calendar',
style: TextStyle(fontFamily: 'MaterialIcons'),
);
You may use it for custom Icon class to integrate with Material Framework smoothly, but in this case you will need a --no-tree-shake-icons flag for build command since non-constant IconData constructor breaks icon tree shaking.
This might help someone in the future.
You do not need to use any Map to create an icon from dynamic name (too much copy-pasting).
Instead of icon names you can use icon's numeric identifier from the Icons Class.
Example:
int iconCode = 58840;
// Will display "Up arrow" icon from the list
Icon(IconData(iconCode, fontFamily: 'MaterialIcons'));
You need a mapping from string to your icon either Icons or FontAwesomeIcons or ...
Map<String, IconData> iconMapping = {
'facebook' : FontAwesomeIcons.facebook,
'twitter' : FontAwesomeIcons.twitter,
'home' : FontAwesomeIcons.home,
'audiotrack' : Icons.audiotrack,
};
#override
Widget build(BuildContext context) {
return Icon(iconMapping [icon], color: HexColor(color));
}
similar question and answer
Trying to dynamically set the Icon based on a JSON string value
Flutter: Show different icons based on value
Try this out. this is exact thing you are looking for.
Widget buildRemoteIcon(){
// var remoteIconData = new RemoteIconData(Icons.add); // -> flutter native material icons
// var remoteIconData = new RemoteIconData("material://Icons.add"); // -> native material icons remotely (dynamically)
// var remoteIconData = new RemoteIconData("https://example.com/svg.svg"); // -> loading remote svg
// var remoteIconData = new RemoteIconData("assets/icons/add.png"); // -> loading local assets
// var remoteIconData = new RemoteIconData("custom-namespace://CustomIcons.icon_name"); // -> (requires pre-usage definition)
var remoteIconData = new RemoteIconData();
return RemoteIcon(icon: remoteIconData, color: Colors.black);
}
https://github.com/bridgedxyz/dynamic/tree/master/flutter-packages/x_icon
https://pub.dev/packages/x_icon
Use This Package From here you can get Material Icons + FontAwesome Icons also you just need to pass the icon name.
https://pub.dev/packages/dynamic_icons

Removing a fMath image properties dialog in ckeditor

I am a bit stuck with this so it would be great if you could help.
I am using Drupal 7 and Ckeditor 4.3. I am developing a site which has fmath equation editor integrated.
I have disabled the image button, as I don't want end users being able to upload their own images. On the other hand, users can use fMath to insert equations. The way fMath handles equation insertion is by inserting a img tag.
When users double click this image or when they right click over the image, they access the image properties dialog, where they can change source url of the image and few other things. On the url input text, they could change the source of the image so that they could insert their own images on the page, which is something I don't want.
The have been working with two different unsuccessful approaches until now trying to solve this problem:
Removing elements from the dialog, as the URL input text on the dialog (and the alt text as well).
Trying to disable the dialog itself.
I'd like to use a custom plugin to accomplish the desired behavior as I have different CKeditor profiles in Drupal.
I haven't been successful. Do you know how could I handle this undesirable behavior?
Ok, I ended up with something like this in the plugin.js file:
CKEDITOR.plugins.add( 'custom_doubleclick',
{
init: function( editor )
{
// First part, dialogDefinition allow us to remove the
// "Link" and "Advanced" tabs on the dialog
CKEDITOR.on( 'dialogDefinition', function( ev ) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
if ( dialogName == 'image' ) {
dialogDefinition.removeContents( 'Link' );
dialogDefinition.removeContents( 'advanced' );
}
});
// Second part, it disables the textUrl and txtAlt input text boxes
editor.on( 'dialogShow', function( ev ) {
var dialog = ev.data;
var dialogName = dialog.getName();
if ( dialogName == 'image' ) {
//var dialog = CKEDITOR.dialog.getCurrent();
// Get a reference to the Link Info tab.
console.log(dialog)
dialog.getContentElement( 'info','txtUrl' ).disable();
dialog.getContentElement( 'info','txtAlt' ).disable();
}
});
}
});
As you can see I didn't disable the dialog itself, but the non useful elements. I hope this can help to someone else.

collectionView, didSelectItemAtIndexPath issue

I have an interesting issue with collectionView, specifically, didSelectItemAtIndexPath.
My app has one particular view with a background image, which is accessed via an SQL. Within that view is a popover, with a collectionView, to change the parent view's background, and access other "sets" available for purchase.
My issue is with the changing of the background. All items display correctly in the collection view and the parent's background will change as it should. The problem is that the item selected is not the one that displays, even though via NSLog, I can see that the correct image is being selected and passed back to the parent. There is a corresponding NSLog in the parent, which shows the same image id as the popover's NSLog.
The first item in the collectionView, when tapped, will change the background of the parent to white, as if there was no image available. Tapping the second cell will display the first cell's image. Tapping the third cell will display the second cell's image... and so on. There are 15 images available to select from.
This is the didSelect method:
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if ([_currentView isEqualToString:#"New_Journal"])
{
MyAppDelegate *appDelegate = (MyAppDelegate *)[UIApplication.sharedApplication delegate];
// to get the variable back to the parent
appDelegate.loadBackgroundID = indexPath.row;
// interact with the SQL via _settingsDao
[_settingsDao updateJournalBackgroundId:_journalId withBackgroundId:appDelegate.loadBackgroundID];
NSLog(#"Selected background: %d", indexPath.row);
// notification to let EntryView know the background has changed
[NSNotificationCenter.defaultCenter postNotificationName:#"aBackgroundChanged" object:self];
}
}
Edit to show SQL interaction method:
-(void)updateJournalBackgroundId:(int)journalID withBackgroundId:(int)newBackgroundId
{
NSString *query = #"UPDATE BgIconBorderSettings SET background_id = ? WHERE journal_id = ?";
FMDatabase *db = [dbUtils sharedDB];
[db executeUpdate:query,[NSNumber numberWithInt:newBackgroundId],[NSNumber numberWithInt:journalID]];
if([db hadError])
{
NSLog(#"Error %d: %#",[db lastErrorCode],[db lastErrorMessage]);
}
}
Anyone have any ideas on how to get the correct image of the tapped cell to display? Thanks for any assistance in solving this issue.
As jhilgert pointed out... it was the SQL database. It started at 1 and not 0. Changed the ids and it works as expected.

flexcroll not working after Extjs window resize

I am using ExtJs 4.1.0 and I am new to extjs. I have used fleXcroll for applying custom scrollbars to windows and panels. They are working fine so far, but when I am trying to resize the window, the scrollbars are not getting updated and also they are getting hidden from the screen.
Here is the code:
var samplePanel=new Ext.panel.Panel({
title:'Panel1',
height:350,
width:350
});
var sampleWindow=new Ext.window.Window({title:'Window',
items:[samplePanel],
renderTo:Ext.getBody(),
height:300,
width:300,
listeners:{
afterLayout:function(c){
fleXenv.fleXcrollMain(c.body.id);
},resize:function(c,w,h,o){
if(c.body.dom.fleXcroll)
fleXenv.updateScrollBars(); }
}
});
Does anyone had similar problem? Please help me.
After struggling for long time I finally found the actual problem.
Let us see what is happening when we apply scrollbars to a window. The contents inside window goes into its body where we need to display the scrollbars. FleXcroll will add two additional divs inside the target div(in this case, body) with ids of the form targetDivID_mcontentwrapper and targetDivID_scrollbarwrapper. The contents of the body will go to _mcontentwrapper and scrollbars will be displayed in the later.
Scrollbars will be displayed if the contentSize is greater that size of contentwrapper-div which is same as target div.
Here is the structure of divs after applying flexcroll
window-body(target div)
-- mcontentwrapper
-- contentwrapper
-- actual content
-- scrollbarwrapper
After resize the window the content is going into window-body rather than contentwrapper. So the content size in contentwrapper will be zero and hence scrollbar disappears.
structure after resize:
window-body(target div)
-- actual content
-- mcontentwrapper
-- contentwrapper
-- scrollbarwrapper
Now we need to put the actual_content into contentwrapper before updating the scrollbars.
Here is the code for doing that:
listeners:{afterLayout:function(c){
fleXenv.fleXcrollMain(c.body.id);
},
resize:function(c){if(c.body.dom.fleXcroll){
var a=c.body.dom.childNodes;
var b=[];
for (var i=0,j=0;i<a.length ;i++ )
{
if(a[i].id!=c.body.id+"_mcontentwrapper" && a[i].id!=c.body.id+"_scrollwrapper")
{
b[j]=a[i];
j++;
}
}
var el=Ext.get(c.body.id+"_contentwrapper");
for(var i=0;i<b.length;i++)
el.appendChild(b[i]);
}
}
}
I hope it is useful.

ExtJS window dynamically add GridPanel items and show it

I want to show only one GridPanel,which I dynamically add by switch click button event, in window.
var event_menu = new Ext.menu.Menu( {
id : "event_menu",
items : [ {
text : 'record1',
handler : function() {
win.add(item_list_panel);//dynamica add GridPanel to show server data
win.doLayout();
item_list_store.load();
}
}, {
text : 'record2',
handler : function() {
win.remove(item_list_panel);//I want to remove it inorder to show the item_list_panel2 and only show one panel.
win.add(item_list_panel2);
win.doLayout();
item_list_store.load();
}
} ]
});
and this menu belong to my window tbar.
when I click record win will show item_list_panel and I want to when I click record2 the item_list_panel2 will show in win and item_list_panel will hide.
If I win.remove(item_list_panel) will have an error :
c.getPositionEl().dom is undefined
How can I do it,Thanks
I can barely understand your question, but if I understand correctly you can do it several ways.
you can destroy the component directly
item_list_panel.destroy()
you can go through your items and select it by id
win.items.item('item_id').destroy()
There are also ways to remove it without completely destroying it, depends what you want to do

Resources