I have a custom view in side the item on the right highlighted in black.
The each view cell has a big gap because of the black custom view. This black view is a grid which was added in the bindingContextChanged function.
public partial class ShiftTemplate : ViewCell
{
public ShiftTemplate()
{
InitializeComponent();
}
}
public class ShiftView : ContentView
{
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
var model = BindingContext as StaffShiftViewModel;
var grid = new Grid();
var shiftCount = 0;
var index = 0;
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star });
foreach (var shift in model.Shifts)
{
grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
var timeLabel = new Label
{
Text = shift.Time,
VerticalTextAlignment = TextAlignment.Center,
HorizontalTextAlignment = TextAlignment.End
};
var clockButton = new Button
{
Text = shift.ClockStatus,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Start,
Command = shift.OnClockingPopupCommand
};
var binding = new Binding();
binding.Source = shift;
binding.Path = nameof(shift.ClockStatus);
binding.Mode = BindingMode.OneWay;
clockButton.SetBinding(Button.TextProperty, binding);
var line = new BoxView { HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.Center, HeightRequest = 1, BackgroundColor = Color.Gray };
grid.Children.Add(timeLabel, 0, 1, shiftCount, shiftCount+1);
grid.Children.Add(clockButton, 1, 2, shiftCount, shiftCount+1);
index += 1;
if (index < model.Shifts.Count)
grid.Children.Add(line, 0, 2, shiftCount + 1, shiftCount + 2);
shiftCount+=2;
}
Content = grid;
ForceLayout();
}
}
Related
I created a health bar for my game in Xcode in swift. I added the health bar to my warrior1. but I wanna change the color of my health bar to yellow, if the healthBar.progress reaches a value <= 0.5 && progressBar.progress >= 0.2 and to red, if healthBar.progress < 0.2
that's my code so far:
var warrior1 = Swordsman(position: CGPoint(x: 20, y: 100))
self.addChild(warrior1)
allUnits.append(warrior1)
var progressBar = ProgressBar(color: SKColor.green, size:CGSize(width:100, height:10))
// progressBar.position = warrior1.position
progressBar.position = CGPoint( x: 3, y: 55)
progressBar.progress = 0.5 // if I change the value, the color has to change too
if (progressBar.progress <= 0.5 && progressBar.progress >= 0.2){
// WHAT SHOULD I WRITE HERE?
}
else if ( progressBar.progress < 0.2){
// AND HERE?
}
warrior1.addChild(progressBar)
And that is my ProgressBar class:
import Foundation
import SpriteKit
class ProgressBar:SKNode {
var background:SKSpriteNode?
var bar:SKSpriteNode?
var _progress:CGFloat = 0
var progress:CGFloat {
get {
return _progress
}
set {
let value = max(min(newValue,1.0),0.0)
if let bar = bar {
bar.xScale = value
_progress = value
}
}
}
convenience init(color:SKColor, size:CGSize) {
self.init()
background = SKSpriteNode(color:SKColor.black,size:size)
bar = SKSpriteNode(color:color,size:size)
if let bar = bar, let background = background {
bar.xScale = 0.0
bar.zPosition = 1.0
bar.position = CGPoint(x:-size.width/2,y:0)
bar.anchorPoint = CGPoint(x:0.0,y:0.5)
addChild(background)
addChild(bar)
}
}
}
Does anyone know what code I have to write in the if and else brackets?
I would be very grateful for an answer.
Plenty of ways to do that but this could be one of them:
var progress: CGFloat {
get {
return _progress
}
set {
let value = max(min(newValue,1.0),0.0)
if let bar = bar {
bar.xScale = value
_progress = value
// Set the color
if value <= 0.2 {
bar.color = .red
} else if // Continue on your own
}
}
}
I've an issue working with custom editor, my editing focus is changed without any action from my part.
Basically, this is a screen of my custom editor in a neutral state (just added empty translation entity):
And this is a screen when my focus got change without reason. As you can see, my editor detected that 2 keys was the same and notify it by a message at the top of the box, the issue is that I was actually editing the second box's "key" field, and my focus changed on the first box (highlighted blue). If I don't display the warning message, I don't have any issue so I guess it comes from there..
This is my custom editor script :
[CustomEditor(typeof(InternationalizationDatabaseSO))]
public class InternationalizationDatabaseSOEditor : Editor
{
#region Constantes
private const string ITEMS_PROPERTY_NAME = "_mItems";
private const string ITEM_CATEGORY_NAME = "_mCategory";
private const string ITEM_KEY_NAME = "_mKey";
private const string ITEM_VALUES_NAME = "_mValues";
private const string ITEM_VALUE_LANGUAGE = "_mLanguage";
private const string ITEM_VALUE_VALUE = "_mValue";
#endregion
#region Attributs
private InternationalizationDatabaseSO _mDatabase;
#endregion
#region Methods
private void OnEnable()
{
Init();
}
private void Init()
{
_mDatabase = target as InternationalizationDatabaseSO;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
SerializedProperty itemsProperty = serializedObject.FindProperty(ITEMS_PROPERTY_NAME);
int arraySize = itemsProperty.arraySize;
EditorGUI.BeginDisabledGroup(false);
{
EditorGUILayout.BeginHorizontal();
{
GUILayout.FlexibleSpace();
if (OnInspectorGUIButton("+", 40, 25, Color.white, Color.green))
{
itemsProperty.arraySize++;
itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1).FindPropertyRelative(ITEM_CATEGORY_NAME).stringValue = "";
itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1).FindPropertyRelative(ITEM_KEY_NAME).stringValue = "";
serializedObject.ApplyModifiedProperties();
Init();
return;
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
for(int i = 0; i < arraySize; i++)
{
if(OnInspectorGUIItem(i) == false)
{
serializedObject.ApplyModifiedProperties();
Init();
return;
}
}
}
EditorGUI.EndDisabledGroup();
serializedObject.ApplyModifiedProperties();
}
private bool OnInspectorGUIItem(int index)
{
SerializedProperty itemsProperty = serializedObject.FindProperty(ITEMS_PROPERTY_NAME);
SerializedProperty itemCategory = itemsProperty.GetArrayElementAtIndex(index).FindPropertyRelative(ITEM_CATEGORY_NAME);
SerializedProperty itemKey = itemsProperty.GetArrayElementAtIndex(index).FindPropertyRelative(ITEM_KEY_NAME);
EditorGUI.indentLevel += 1;
EditorGUILayout.BeginVertical(GUI.skin.box);
{
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.BeginVertical();
{
if(KeyAlreadyExist(index, itemKey.stringValue))
{
OnInspectorGUIText("Key already exists", 12, Color.red, FontStyle.Bold, false);
}
OnInspectorGUIText("Key : " + itemKey.stringValue, 12, FontStyle.Normal, false);
}
EditorGUILayout.EndVertical();
GUILayout.FlexibleSpace();
if(OnInspectorGUIButton("-", 40, 25, Color.white, Color.red))
{
itemCategory.stringValue = "";
itemKey.stringValue = "";
itemsProperty.DeleteArrayElementAtIndex(index);
return false;
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
EditorGUILayout.BeginVertical();
{
GUIStyle style = EditorStyles.foldout;
style.fontSize = 15;
style.fontStyle = FontStyle.Bold;
itemCategory.isExpanded = EditorGUILayout.Foldout(itemCategory.isExpanded, "General informations", style);
if(itemCategory.isExpanded)
{
EditorGUILayout.Space();
EditorGUILayout.PropertyField(itemCategory, new GUIContent("Category"));
EditorGUILayout.PropertyField(itemKey, new GUIContent("Key"));
}
if(OnInspectorGUIItemLanguage(index, itemsProperty.GetArrayElementAtIndex(index)) == false)
{
return false;
}
}
EditorGUILayout.EndVertical();
}
EditorGUILayout.EndVertical();
EditorGUI.indentLevel -= 1;
return true;
}
private bool OnInspectorGUIItemLanguage(int index, SerializedProperty propertyItem)
{
EditorGUILayout.BeginVertical();
{
GUIStyle style = EditorStyles.foldout;
style.fontSize = 15;
style.normal.textColor = Color.black;
style.fontStyle = FontStyle.Bold;
SerializedProperty itemValues = propertyItem.FindPropertyRelative(ITEM_VALUES_NAME);
itemValues.isExpanded = EditorGUILayout.Foldout(itemValues.isExpanded, "Languages informations", style);
if(itemValues.isExpanded)
{
EditorGUILayout.Space();
EditorGUILayout.BeginVertical();
{
EditorGUILayout.BeginHorizontal();
{
int nbTranslation = itemValues.arraySize;
EditorGUILayout.LabelField("Nb translation : " + nbTranslation);
GUILayout.FlexibleSpace();
if (OnInspectorGUIButton("+", 20, 20, Color.white, Color.green))
{
itemValues.arraySize++;
itemValues.GetArrayElementAtIndex(itemValues.arraySize - 1).FindPropertyRelative(ITEM_VALUE_LANGUAGE).intValue = 0;
itemValues.GetArrayElementAtIndex(itemValues.arraySize - 1).FindPropertyRelative(ITEM_VALUE_VALUE).stringValue = "";
return false;
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
if (itemValues.arraySize > 0)
{
string translatedLanguages = "{";
foreach (InternationalizationDatabaseItemLanguage item in _mDatabase.Items[index].Values)
{
translatedLanguages += item.Language.ToString() + ", ";
}
if (translatedLanguages.Length > 2)
{
translatedLanguages = translatedLanguages.Remove(translatedLanguages.Length - 2);
}
translatedLanguages += "}";
//EditorStyles.label.stretchHeight = true;
EditorStyles.label.wordWrap = true;
EditorGUILayout.LabelField("Translated : \n" + translatedLanguages);
EditorGUILayout.Space();
for (int i = 0; i < itemValues.arraySize; i++)
{
EditorGUILayout.BeginVertical(GUI.skin.box);
{
EditorGUILayout.Space();
InternationalizationDatabaseItemLanguage item = _mDatabase.Items[index].Values[i];
SerializedProperty propLanguage = itemValues.GetArrayElementAtIndex(i).FindPropertyRelative(ITEM_VALUE_LANGUAGE);
SerializedProperty propValue = itemValues.GetArrayElementAtIndex(i).FindPropertyRelative(ITEM_VALUE_VALUE);
EditorGUILayout.BeginHorizontal();
{
if (LanguageAlreadyExist(index, i, _mDatabase.Items[index].Values[i].Language))
{
OnInspectorGUIText("Warning language translation already exist", 12, Color.red, FontStyle.Bold, false);
}
GUILayout.FlexibleSpace();
if (OnInspectorGUIButton("-", 20, 20, Color.white, Color.red))
{
itemValues.DeleteArrayElementAtIndex(i);
return false;
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
EditorGUILayout.PropertyField(propLanguage, new GUIContent("Language"));
EditorGUILayout.PrefixLabel("Translation");
propValue.stringValue = EditorGUILayout.TextArea(propValue.stringValue, GUILayout.Height(80));
}
EditorGUILayout.Space();
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
}
}
}
EditorGUILayout.EndVertical();
}
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
return true;
}
private bool KeyAlreadyExist(int currentIndex, string key)
{
for(int i = 0; i < _mDatabase.Items.Count; i++)
{
InternationalizationDatabaseItem item = _mDatabase.Items[i];
if(currentIndex != i && item.Key == key && string.IsNullOrEmpty(key) == false)
{
return true;
}
}
return false;
}
private bool LanguageAlreadyExist(int indexInDatabase, int currentIndex, SystemLanguage language)
{
for (int i = 0; i < _mDatabase.Items[indexInDatabase].Values.Count; i++)
{
InternationalizationDatabaseItemLanguage item = _mDatabase.Items[indexInDatabase].Values[i];
if (currentIndex != i && item.Language == language)
{
return true;
}
}
return false;
}
private void OnInspectorGUIText(string text, FontStyle fontStyle, bool prefixLabel)
{
GUIStyle style = new GUIStyle();
style.fontStyle = fontStyle;
style.wordWrap = true;
if (prefixLabel)
{
EditorGUILayout.PrefixLabel(text, GUIStyle.none, style);
}
else
{
EditorGUILayout.LabelField(text, style);
}
}
private void OnInspectorGUIText(string text, int fontSize, FontStyle fontStyle, bool prefixLabel)
{
GUIStyle style = new GUIStyle();
style.fontSize = fontSize;
style.fontStyle = fontStyle;
style.wordWrap = true;
if (prefixLabel)
{
EditorGUILayout.PrefixLabel(text, GUIStyle.none, style);
}
else
{
EditorGUILayout.LabelField(text, style);
}
}
private void OnInspectorGUIText(string text, int fontSize, Color textColor, FontStyle fontStyle, bool prefixLabel)
{
GUIStyle style = new GUIStyle();
style.fontSize = fontSize;
style.normal.textColor = textColor;
style.fontStyle = fontStyle;
style.wordWrap = true;
if(prefixLabel)
{
EditorGUILayout.PrefixLabel(text, GUIStyle.none, style);
}
else
{
EditorGUILayout.LabelField(text, style);
}
}
private bool OnInspectorGUIButton(string label, int width, int height, Color textColor, Color backgroundColor)
{
Color saveColor = GUI.backgroundColor;
GUILayoutOption[] options = { GUILayout.Width(width), GUILayout.Height(height) };
GUIStyle style = new GUIStyle(GUI.skin.button);
style.normal.textColor = textColor;
GUI.backgroundColor = backgroundColor;
bool pressed = GUILayout.Button(label, style, options);
GUI.backgroundColor = saveColor;
return pressed;
}
#endregion
}
Have you any suggestion ? Thanks
Have a nice day.
Are you sure you are not sharing reference to the same property in both boxes ?
Ok finally figured it out, I mean, I'm not still totally certain why it happens, but found a workaround thanks to : https://forum.unity.com/threads/editor-gui-inputfield-loses-focus-when-gui-updates.542147/
Basically, I'm just displaying always the LabelField, but if there is no error, I simply set the errorMessage to an empty string
I'm trying to create a candlestick chart using Charts
As you guys can notice from my screenshot, the chart only shows the highest and lowest values instead of displaying the values for all the candles. Is there any way I can implement that with the Charts framework?
Thanks in advance.
If you want to display only highest and lowest values, you need to implement you own renderer inherited from CandleStickChartRenderer. In fact you just need to override one function drawValues(context: CGContext).
I have made some example which contain a hundred lines of code, but in fact my custom code contains about thirty lines.
class MyCandleStickChartRenderer: CandleStickChartRenderer {
private var _xBounds = XBounds() // Reusable XBounds object
private var minValue: Double
private var maxValue: Double
// New constructor
init (view: CandleStickChartView, minValue: Double, maxValue: Double) {
self.minValue = minValue
self.maxValue = maxValue
super.init(dataProvider: view, animator: view.chartAnimator, viewPortHandler: view.viewPortHandler)
}
// Override draw function
override func drawValues(context: CGContext)
{
guard
let dataProvider = dataProvider,
let candleData = dataProvider.candleData
else { return }
guard isDrawingValuesAllowed(dataProvider: dataProvider) else { return }
var dataSets = candleData.dataSets
let phaseY = animator.phaseY
var pt = CGPoint()
for i in 0 ..< dataSets.count
{
guard let dataSet = dataSets[i] as? IBarLineScatterCandleBubbleChartDataSet
else { continue }
let valueFont = dataSet.valueFont
let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency)
let valueToPixelMatrix = trans.valueToPixelMatrix
_xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator)
let lineHeight = valueFont.lineHeight
let yOffset: CGFloat = lineHeight + 5.0
for j in stride(from: _xBounds.min, through: _xBounds.range + _xBounds.min, by: 1)
{
guard let e = dataSet.entryForIndex(j) as? CandleChartDataEntry else { break }
guard e.high == maxValue || e.low == minValue else { continue }
pt.x = CGFloat(e.x)
if e.high == maxValue {
pt.y = CGFloat(e.high * phaseY)
} else if e.low == minValue {
pt.y = CGFloat(e.low * phaseY)
}
pt = pt.applying(valueToPixelMatrix)
if (!viewPortHandler.isInBoundsRight(pt.x))
{
break
}
if (!viewPortHandler.isInBoundsLeft(pt.x) || !viewPortHandler.isInBoundsY(pt.y))
{
continue
}
if dataSet.isDrawValuesEnabled
{
// In this part we draw min and max values
var textValue: String?
var align: NSTextAlignment = .center
if e.high == maxValue {
pt.y -= yOffset
textValue = "← " + String(maxValue)
align = .left
} else if e.low == minValue {
pt.y += yOffset / 5
textValue = String(minValue) + " →"
align = .right
}
if let textValue = textValue {
ChartUtils.drawText(
context: context,
text: textValue,
point: CGPoint(
x: pt.x,
y: pt.y ),
align: align,
attributes: [NSAttributedStringKey.font: valueFont, NSAttributedStringKey.foregroundColor: dataSet.valueTextColorAt(j)])
}
}
}
}
}
}
Do not forget use you custom renderer for you chart. ;)
myCandleStickChartView.renderer = MyCandleStickChartRenderer(view: myCandleStickChartView, minValue: 400, maxValue: 1450)
I found how to calculate dynamic uiwebview height according to its content. My code is :
println("webViweDidFinish started")
var frame:CGRect = myWebView.frame
frame.size.height = 1
var fittingSize :CGSize = myWebView.sizeThatFits(CGSizeZero)
frame.size = fittingSize
myWebView.frame = frame
var contentsizeHeight = webView.scrollView.contentSize.height
var yCoordinateOfWebView = myWebView.frame.origin.y
var contentHeight: CGFloat = webView.scrollView.contentSize.height;
myScrollView.contentSize = CGSizeMake(self.view.frame.width, yCoordinateOfWebView + contentsizeHeight + labelAuthorOfArticle.frame.height) //
UIView.animateWithDuration(0.5, animations: {
self.heightConstraints.constant = fittingSize.height
self.myWebView.layoutIfNeeded()
self.myScrollContentView.layoutIfNeeded()
})
self.activityIndicator.stopAnimating()
If I use this approach:
var height:NSString! = webView.stringByEvaluatingJavaScriptFromString("document.height;")
var heightInFloat = height.floatValue
How to convert height to CGFloat? I can only convert it to float as you see.
The problem is that when webview has too many images the height is calculated wrong. Oppositely when there is no image height is calculated right. When I reload the function, the second time it calculates right (with images). Here is content of string that I am loading:
class func formatContentText(inout text: NSString)-> NSString{
text = text.stringByReplacingOccurrencesOfString("src=\"", withString: "src=\"http://dixinews.kz")
var deviceWidth = "300"
text = "<html><head><meta name = \"viewport\" content = \"user-scalable=no, width=" + deviceWidth + " , maximum-scale=1.0\"><style>img{max-width:100%%;height:auto !important;width:auto !important;};</style></head><body>" + text + "</body></html>"
return text
}
I used approach with javascript. Here is my code:
func webViewDidFinishLoad(webView: UIWebView) {
var frame:CGRect = myWebView.frame
// javascript
var height:NSString! = webView.stringByEvaluatingJavaScriptFromString("document.height;")
var heightInFloat = height.floatValue // convert to float
var heightINCGFloat = CGFloat(heightInFloat) convert to cgfloat
frame.size.height = heightINCGFloat //set heigh
myWebView.frame = frame // set frame
myWebView.scrollView.contentSize.height = myWebView.frame.height
var contentsizeHeight = webView.scrollView.contentSize.height
var yCoordinateOfWebView = myWebView.frame.origin.y
myScrollView.contentSize = CGSizeMake(self.view.frame.width, yCoordinateOfWebView + contentsizeHeight + labelAuthorOfArticle.frame.height) //
UIView.animateWithDuration(0.5, animations: {
self.heightConstraints.constant = heightINCGFloat
self.myWebView.layoutIfNeeded()
self.myScrollContentView.layoutIfNeeded()
})
self.activityIndicator.stopAnimating()
}
i am making a game in which i am using is-clicked function when i click the object the letter written on it displayed now i want that when i clicked the same object again the word disappear... now how can i do that?
#pragma strict
static var nextPos = 200;
var word: String;
var sel: String;
var isClicked : boolean=false;
var xpos: float = 200;
function OnMouseDown()
{
if (!isClicked) {
isClicked = true;
xpos = nextPos;
nextPos += 8;
}
}
function OnGUI()
{
if (gameObject.name == "Sphere(Clone)" && isClicked )
{
GUI.Label(new Rect(xpos,260,400,100), "A");
}
else if (gameObject.name == "Sphere 1(Clone)" && isClicked )
{
GUI.Label(new Rect(xpos,260,400,100), "B");
}
else if (gameObject.name == "Sphere 2(Clone)" && isClicked )
{
GUI.Label(new Rect(xpos,260,400,100), "C");
}
else if (gameObject.name == "Sphere 3(Clone)" && isClicked )
{
GUI.Label(new Rect(xpos,260,400,100), "D");
}
}
write in OnMouseDown
else if(isClicked)
{
isClicked = false;
// do your xpos stuff here
}