Xamarin: iOS 7 UITextField Padding - ios7

What's the "easiest" way to add padding (all four sides) to a UITextField in Xamarin for iOS 7. Following code doesn't seem to work on iOS7.
textField.LeftView = new UIView (new RectangleF (0, 0, 10, 10));
textField.LeftViewMode = UITextFieldViewMode.Always;
Then I tried to subclass UITextField to try another option...
public class TextFieldBase : UITextField
{
public TextFieldBase (IntPtr handle) : base (handle)
{
}
public override RectangleF TextRect(RectangleF bounds){
return RectangleF.Inflate( bounds , 10 , 10 );
}
public override RectangleF EditingRect(RectangleF bounds){
return RectangleF.Inflate( bounds , 10 , 10 );
}
}
That didn't work either.
I'm not sure if what I have set in the interface builder is overriding what I have in the subclass code.

Subclass UITextField and override TextRect, EditingRect:
public override CoreGraphics.CGRect EditingRect (CoreGraphics.CGRect forBounds) {
return base.EditingRect (InsetRect (forBounds, new UIEdgeInsets (0, 10, 0, 10)));
}
public static CoreGraphics.CGRect InsetRect(CoreGraphics.CGRect rect, UIEdgeInsets insets)
{
return new CoreGraphics.CGRect(rect.X + insets.Left, rect.Y + insets.Top,
rect.Width - insets.Left - insets.Right, rect.Height - insets.Top - insets.Bottom );
}

You might want to try subclassing UITextField and overriding the following methods:
- (CGRect)textRectForBounds and -(CGRect)editingRectForBounds.
You can then adjust the bounds, height, and width to get the desired effect.

Related

How to pin NSViewController to top of NSPopover during NSViewController.transition?

I've been trying to create a sliding transition from one child view controller to another inside an NSPopover.
My problem is that the child view controllers do not stick to the top of the NSPopover during the transition. They animate in from the bottom or top:
Expected behaviour: both child view controllers should stick to the top during the transition and should simply slide over horizontally.
This is the function I wrote to trigger the transition:
func loadViewController(_ childViewController: NSViewController, withTransition transitionOptions: NSViewController.TransitionOptions?) {
addChild(childViewController)
view.addSubview(childViewController.view)
childViewController.view.layer?.borderColor = NSColor(calibratedRed: 0, green: 255, blue: 0, alpha: 1).cgColor
childViewController.view.layer?.borderWidth = 2
childViewController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
view.layout()
let oldViewController = currentViewController
currentViewController = childViewController
oldViewController?.view.layer?.borderColor = NSColor(calibratedRed: 255, green: 0, blue: 0, alpha: 1).cgColor
oldViewController?.view.layer?.borderWidth = 2
if let oldViewController = oldViewController {
transition(from: oldViewController, to: currentViewController!, options: transitionOptions ?? .slideLeft, completionHandler: { [weak oldViewController] in
oldViewController?.removeFromParent()
oldViewController?.view.removeFromSuperview()
})
}
NSAnimationContext.runAnimationGroup({ (context) -> Void in
context.duration = 0.5
context.allowsImplicitAnimation = true
self.parentPopover?.contentSize = NSSize(width: childViewController.preferredContentSize.width, height: childViewController.preferredContentSize.height)
})
}
Any idea what could be causing the issue? I've tried playing around with the constraints of both the child and parent view controllers as well as their frame sizes. I just can't figure out what I'm doing wrong.
I've uploaded the complete reproducible example here: https://github.com/maximilianschmitt/DebugPopoverAnimation
MasterViewController.swift
ChildViewController.swift
Thanks a lot for your help!
If you expect as on below animation
then just remove update of content size from animation block, as below
self.parentPopover?.contentSize = NSSize(width: childViewController.preferredContentSize.width, height: childViewController.preferredContentSize.height)
NSAnimationContext.runAnimationGroup({ (context) -> Void in
context.duration = 0.5
context.allowsImplicitAnimation = true
}) {
oldViewController?.removeFromParent()
oldViewController?.view.removeFromSuperview()
}
Update: keep popover content animatable (above changes are not needed)
For this case the only you need is to flip coordinate system for popover content view (which is a view of MasterViewController)
class PopoverContentView: NSView {
override var isFlipped: Bool { true }
}
class MasterViewController: NSViewController {
...
override func loadView() {
self.view = PopoverContentView()
}

React Native native UI component width and height

I'm creating a native UI component on iOS and I want its size to expand according to the content size.
It seems like I must set a fixed width and height in order for the view to be rendered. Any idea how to solve it?
// JS
import React from 'react';
import { View, requireNativeComponent } from 'react-native';
class StyledText extends React.Component {
render() {
return (
<View style={this.props.style}>
// without the height and width the compnent won't show up
<StyledLabelReactBridge styledText={'some text'} style={{height: 100, width: 100, backgroundColor: 'red'}}/>
</View>
);
}
}
StyledText.propTypes = {
styledText: React.PropTypes.string,
style: View.propTypes.style
};
const StyledLabelReactBridge = requireNativeComponent('StyledLabelReactBridge', StyledText);
module.exports = StyledText;
// objective-C
#implementation StyledLabelReactBridgeManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
return [[NewStyledLabel alloc] init];
}
RCT_CUSTOM_VIEW_PROPERTY(styledText, NSString, NewStyledLabel)
{
if (![json isKindOfClass:[NSString class]])
return;
[view setStyledText:[NewStyledText textFromXHTML:json]];
}
#end
You need to override reactSetFrame in xcode to receive content size change.
#import "React/UIView+React.h"
#implementation YourView {
- (void)reactSetFrame:(CGRect)frame {
[super reactSetFrame: frame];
/* everytime content size changes, you will get its frame here. */
}
}
first you should create a subclass of RCTShadowView like
#import <React/RCTShadowView.h>
#interface RNGuessLikeContainerShadowView : RCTShadowView
#end
#implementation RNGuessLikeContainerShadowView
- (void)setLocalData:(NSObject *)localData {
if ([localData isKindOfClass:[NSNumber class]]) {
[self setIntrinsicContentSize:CGSizeMake(UIScreen.mainScreen.bounds.size.width, ((NSNumber *)localData).floatValue)];
}
}
#end
then create subclass of RCTViewManager and return shadowview and view of you custom class instance
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerUtils.h>
#interface RNGuessLikeModule: RCTViewManager <RNGuessLikeContainerViewHeightUpdater>
#end
#implementation RNGuessLikeModule
RCT_EXPORT_MODULE(RNGuessLikeModule)
RCT_EXPORT_VIEW_PROPERTY(objects, NSString);
- (UIView *)view {
RNGuessLikeContainerView *_view = [RNGuessLikeContainerView new];
_view.delegate = self;
return _view;
}
- (RCTShadowView *)shadowView {
return [RNGuessLikeContainerShadowView new];
}
- (void)didUpdateWithHeight:(CGFloat)height view:(RNGuessLikeContainerView *)view {
RCTExecuteOnUIManagerQueue(^{
RCTShadowView *shadowView = [self.bridge.uiManager shadowViewForReactTag:view.reactTag];
[shadowView setLocalData:#(height)];
[self.bridge.uiManager setNeedsLayout];
});
}
#end
and in mine code i set custom native ui view delegate to RNGuessLikeModule which is subclass of RCTViewManager,
and you can caculate size in you custom view when data from rn module passed
#objc
public protocol RNGuessLikeContainerViewHeightUpdater {
func didUpdate(height: CGFloat, view: RNGuessLikeContainerView)
}
public final class RNGuessLikeContainerView: UIView, GuessLikeItemsComponentContainer {
#objc
public var objects: String? {
didSet {
if let _objects = objects,
let _data = _objects.data(using: .utf8, allowLossyConversion: true) {
reload(objects: _data)
}
}
}
#objc
public weak var delegate: RNGuessLikeContainerViewHeightUpdater?
public var controller: UIViewController {
return reactViewController()
}
public var guessLikeSceneType: GuessLikeSceneType = .邀好友赚现金红包
public var guessLikeTitle: String?
public var guessLikeItems: [GuessLikeItemsSectionSubItem] = []
public var routerInfo: String?
#objc
public private(set) var guessLikeHeight: CGFloat = 0
lazy var backend = GuessLikeItemsComponentContainerBackend(parent: self)
public lazy var guessLikeContainer: UICollectionView = {
let _container = createGuessLikeContainer()
_container.dataSource = backend
_container.delegate = backend
addSubview(_container)
return _container
}()
override public func layoutSubviews() {
super.layoutSubviews()
guessLikeContainer.frame = bounds
}
public func reload(objects: Data) {
precondition(pthread_main_np() != 0, "RNGuessLikeContainerView reload method should be called on main thread")
do {
let _items = try JSONDecoder().decode([ItemListModel].self, from: objects)
guessLikeItems = GuessLikeItemsSectionItem(list: _items).items
guessLikeContainer.reloadData()
updateHeight()
} catch {
debugPrint(error)
}
}
public func append(objects: Data) {
precondition(pthread_main_np() != 0, "RNGuessLikeContainerView append method should be called on main thread")
if let _list = try? JSONDecoder().decode([ItemListModel].self, from: objects) {
let _items = GuessLikeItemsSectionItem(list: _list).items
guessLikeItems.append(contentsOf: _items)
guessLikeContainer.reloadData()
updateHeight()
}
}
func updateHeight() {
if guessLikeItems.isEmpty {
guessLikeHeight = 0
} else {
var leftHeight: CGFloat = 0
var rightHeight: CGFloat = 0
for (index, item) in guessLikeItems.enumerated() {
if index % 2 == 0 {
leftHeight += item.height + 10.0
} else {
rightHeight += item.height + 10.0
}
}
let sectionHeaderHeight: CGFloat = 50.0
guessLikeHeight = max(leftHeight, rightHeight) + sectionHeaderHeight
}
if let _delegate = delegate {
_delegate.didUpdate(height: guessLikeHeight, view: self)
}
}
public override var intrinsicContentSize: CGSize {
return CGSize(width: UIScreen.main.bounds.width, height: guessLikeHeight)
}
}
then find shadowview binded to your custom ui view and update intrinsicContentSize
finaly call [self.bridge.uiManager setNeedsLayout]
may help you
#implementation SNBFundCardViewManager
RCT_EXPORT_MODULE(FundCard)
- (UIView *)view
{
return [[SNBFundHomeFundCardCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#""];
}
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
RCT_CUSTOM_VIEW_PROPERTY(data, NSDictionary, SNBFundHomeFundCardCell)
{
view.rnData = json;
// 自己撑起高度
CGFloat height = [view.vm getCellHeight];
[self.bridge.uiManager setIntrinsicContentSize:CGSizeMake(UIViewNoIntrinsicMetric, height) forView:view];
}
Well, couldn't find 'auto' like behavior, how ever, setting the component to:
{{ width: '100%', height: '100%}}
Makes it expand (and shrink) according to the parent, which is good enough for my use case. It's a shame that setting 'flex: 1' doesn't have the same effect.

func collectionViewContentSize in Swift3

I have update my Project to Swift3 in Xcode 8 and it comes this error but I have no idea what I can make there. I have already search in google but nothing founded.
Have anyone an Idea what I can make ?
Here the Error:
Method 'collectionViewContentSize()' with Objective-C selector 'collectionViewContentSize' conflicts with getter for 'collectionViewContentSize' from superclass 'UICollectionViewLayout' with the same Objective-C selector
public func collectionViewContentSize() -> CGSize {
let numberOfSections = collectionView?.numberOfSections
if numberOfSections == 0 {
return CGSize.zero
}
var contentSize = collectionView?.bounds.size
contentSize?.height = CGFloat(columnHeights[0])
return contentSize!
}
I had something similar but I was overriding collectionViewContentSize()
override func collectionViewContentSize() -> CGSize {
let collection = collectionView!
let width = collection.bounds.size.width
let height = max(posYColumn1, posYColumn2)
return CGSize(width: width, height: height)
}
I Downloaded XCode 8 beta 4 today and have had to change it to:
override var collectionViewContentSize: CGSize {
let collection = collectionView!
let width = collection.bounds.size.width
let height = max(posYColumn1, posYColumn2)
return CGSize(width: width, height: height)
}

MPAndroidChart MarkerView in fixed position

Is there any way to have fixed position for MarkerView? I need to have it fixed in top left or top right corner.
This is one approach to fix the marker on the Top Left or Top Right
Once you've created the custom MarkerView here's what you can do.
1) You can set an id to the parent view/layout and using that id you can get it's width.
layoutWidth = customLayout.getWidth();
2) You can then override draw and do the following:
#Override
public void draw(Canvas canvas, float posX, float posY) {
if (posX > (canvas.getWidth() / 2.0))
//Check if the user is in the right half of the canvas
super.draw(canvas, leftXPos, leftYPos);
//Draw marker on the left top corner
else
//Otherwise draw the marker on the top right corner.
super.draw(canvas, canvas.getWidth() - layoutWidth, rightYPos);
}
You can set the values for leftXPos, leftYPos and rightYPos to whatever looks and feels best.
Hope this helps!
You should create a custom MarkerView, like in the documentation.
Then, customize getXOffset and getYOffset like this:
#Override
public int getXOffset(float xpos) {
// this will cause the marker-view to be at left of the screen
return -(int)xpos;
}
#Override
public int getYOffset(float ypos) {
// this will cause the marker-view to be at top screen
return -(int)ypos;
getXOffset(float xpos) and getYOffset(float ypos) are not overridden by the MarkerView class anymore. To fix the Marker position, You have to override the getOffsetForDrawingAtPoint(float posX, float posY) method in the following way:
private MPPointF mOffset;
#Override
public MPPointF getOffsetForDrawingAtPoint(float posX, float posY) {
if(mOffset == null) {
// center the marker horizontally and fixed Y position at the top
mOffset = new MPPointF(-(getWidth() / 2f), -posY);
}
return mOffset;
}
MpandroidChart v3.1.0 :
class MarkerView constructor(
context: Context,
) :
MarkerView(context, R.layout.marker_view) {
private val totalWidth = resources.displayMetrics.widthPixels
override fun refreshContent(e: Entry?, highlight: Highlight?) {
//...
super.refreshContent(e, highlight)
}
override fun getOffsetForDrawingAtPoint(posX: Float, posY: Float): MPPointF {
val supposedX = posX + width
val mpPointF = MPPointF()
mpPointF.x = when {
supposedX > totalWidth -> -width.toFloat()
posX - width < 0 -> 0f
else -> 0f
}
mpPointF.y = if (posY > height)
-height.toFloat()
else
0f
return mpPointF
}
}
in this implementation the default location for MarkerView is to the top-right of the point, if there is enough space, else may be to top-left , bottom-left or bottom-right of it .you can change this behaviour based on your needs.
notice that this only Workes if chart's width is set to MATCH_PARENT.

MT.Dialog FloatElement is not responsive

I've added a floatElement to a root section, but when running the app, it seems that the slider is kind of unresponsive. I have to press multiple times to move the slider.
RootElement root = new RootElement (title)
{
new Section("Weight")
{
new FloatElement(null, null, 0.5f);
}
};
The problem is both on my physical device and in the simulator - both running iOS 7.
Any clues?
Ok, I've got a solution (of sorts). I created my own FloatElement (using the Monodialog source from github) and used my own slider inside it. I borrowed a tip from here
http://www.mpatric.com/2009-04-15-more-responsive-sliders-on-the-iphone
to come up with this, which works, but does feel a bit hacky. Not sure why the behaviour has changed in iOS7 though.
public class Slidy : UISlider
{
private static int THUMB_SIZE = 10;
private static int EFFECTIVE_THUMB_SIZE = 20;
public Slidy(RectangleF r)
: base(r)
{
}
public override bool PointInside(PointF point, UIEvent uievent)
{
var bounds = this.Bounds;
bounds = RectangleF.Inflate(bounds, 25, 25);
return bounds.Contains(point);
}
public override bool BeginTracking(UITouch touch, UIEvent uievent)
{
var bounds = this.Bounds;
float thumbPercent = (this.Value - this.MinValue) / (this.MaxValue - this.MinValue);
float thumbPos = THUMB_SIZE + (thumbPercent * (bounds.Size.Width - (2 * THUMB_SIZE)));
var touchPoint = touch.LocationInView(this);
return (touchPoint.X >= (thumbPos - EFFECTIVE_THUMB_SIZE) &&
touchPoint.X <= (thumbPos + EFFECTIVE_THUMB_SIZE));
}
}