Make UITexftField like android using subclass in swift without any third party - android

How to creat Uitextfield look like android text field

I found this solution, it's working for me.
Follow below step for customise UITextField like android textfield using subclass.
Create new filed with subclass UITextField
for Border below UITextField : set tint color and lineWidthas you want.
override var tintColor: UIColor! {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
let startingPoint = CGPoint(x: rect.minX, y: rect.maxY)
let endingPoint = CGPoint(x: rect.maxX, y: rect.maxY)
let path = UIBezierPath()
path.move(to: startingPoint)
path.addLine(to: endingPoint)
path.lineWidth = 2.0
tintColor.setStroke()
path.stroke()
}
assign UItextFieldDelegate
Enter below code for asking delegate for this subclass
override func awakeFromNib() {
self.delegate = self
}
Also enter text field delegate method textFieldDidBeginEditing and textFieldDidEndEditing.
//MARK: - Textfield Delegate
func textFieldDidBeginEditing(_ textField: UITextField) {
for view in (textField.superview?.subviews)!{
if view is UILabel && view.tag == 0{
let lbl = view as! UILabel
lbl.isHidden = false
textField.placeholder = ""
}
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
if newdelegate != nil{
newdelegate?.textFieldDidEndEditing!(textField)
}
if textField.text?.length == 0{
for view in (textField.superview?.subviews)!{
if view is UILabel && view.tag == 0{
let lbl = view as! UILabel
lbl.isHidden = true
textField.placeholder = lbl.text
}
}
}
}
Make structure in storyboard and assign this subclass to this UItextField
Hope it's helpful to you
Thank you enjoy. :)

First in your xib file go to attributes inspection.
Open right pane.
Select attributes inspection
In border style apply none i.e select one with dotted lines.
After that in your swift file add following method:
func textViewUnderline(textField: UITextField)**
{
let border = CALayer()
let width = CGFloat(1.0)
border.borderColor = UIColor.yourColorforBorderHere.cgColor
border.frame = CGRect(x: 0, y: textField.frame.size.height - width,
width: textField.frame.size.width, height: textField.frame.size.height)
border.borderWidth = width
textField.layer.masksToBounds = true
textField.layer.addSublayer(border)
}
Call this method by passing your uitextfield in viewDidLoad as:
override func viewDidLoad()
{
super.viewDidLoad()
textViewUnderline(textField: yourUITextField)
}

Related

To change text color and background color for an annotated in TextClickableText after it is clicked

I would like to change the text color and the background color of an annotated clickable text.
I looked into the examples for clickable text in google developer but did not find anything related to this.
ClickableText(
text = annotatedText,
onClick = { offset ->
// We check if there is an *URL* annotation attached to the text
// at the clicked position
annotatedText.getStringAnnotations(tag = "URL", start = offset,
end = offset)
.firstOrNull()?.let { annotation ->
// To change the text color when it is clicked <<<<<<<<<<<<< here
}
}
)
What I want to do is to highlight the word the user has clicked.
For example:
If the user clicks the first letter "Text", it would look like the following.
Although I don't think this is very efficient, this code should do the trick:
#Composable
fun SelectableText(
annotatedText: AnnotatedString,
onTextClicked: (Int) -> Unit,
) {
ClickableText(
text = annotatedText,
onClick = { offset ->
annotatedText.spanStyles.indexOfFirst {
it.start <= offset && offset <= it.end
}.takeIf { it != -1 }?.also {
onTextClicked(it)
}
}
)
}
#Composable
fun View() {
var annotatedText by remember {
mutableStateOf(AnnotatedString("Test", listOf(AnnotatedString.Range(SpanStyle(), 0, 4))))
}
SelectableText(annotatedText, onTextClicked = {
val styles = annotatedText.spanStyles.toMutableList()
styles[it] = styles[it].copy(SpanStyle(background = Color.Cyan))
annotatedText = AnnotatedString(annotatedText.text, styles, annotatedText.paragraphStyles)
})
}
A custom SelectableText #Composable is created, with a callback which is called when a span is clicked. I am using spans and not annotations because this is where the style is defined.
When clicked, the parent #Composable (here, View) reacts to the event, grabs a copy of the spanStyles and modifies the one which was clicked. Then it updates the annotatedText. (You might want to "turn off" the selection on the rest of spans.)

Color from hex string in jetpack compose

How to parse hex string e.g. #9CCC65 in Color class in jetpack compose.
P.S: option seem to be missing in jetpack compose package
Current Workaround:
Exported parseColor() method from standard Color class.
#ColorInt
fun parseColor(#Size(min = 1) colorString: String): Int {
if (colorString[0] == '#') { // Use a long to avoid rollovers on #ffXXXXXX
var color = colorString.substring(1).toLong(16)
if (colorString.length == 7) { // Set the alpha value
color = color or -0x1000000
} else require(colorString.length == 9) { "Unknown color" }
return color.toInt()
}
throw IllegalArgumentException("Unknown color")
}
Instead of passing as String instead pass as Hexadecimal. For example if you want this #9CCC65 Color just remove the front # and replace it with 0xFF. Example
val PrimaryBlue = Color(0xFF9CCC65)
You can use this object class with a getColor method.
object HexToJetpackColor {
fun getColor(colorString: String): Color {
return Color(android.graphics.Color.parseColor("#" + colorString))
}
}
Or we can use an extension function
fun Color.fromHex(color: String) = Color(android.graphics.Color.parseColor("#" + colorString))
Jetpack Color class i.e androidx.ui.graphics.Color only takes RGB, ARGB, ColorSpace and colorInt in constructor. See: Color.kt
so, here we are directly accessing parseColor() method from android.graphics.Color which returns colorInt.
Hence parseColor() method can be used to get colorInt and then providing it to Jetpack Color class to get androidx.ui.graphics.Color object.
Similar to Int.dp, there can be String.color extenstion property.
val String.color
get() = Color(android.graphics.Color.parseColor(this))
This can be used as member property on color hex String.
"#FF0000".color
Another option is to write an extension function similar to how android.graphics.Color works:
import androidx.compose.ui.graphics.Color
fun Color.Companion.parse(colorString: String): Color =
Color(color = android.graphics.Color.parseColor(colorString))
Then you can write your compose like this:
Modifier.background(Color.parse("#FF0000"))
I also had this problem and I finally found the solution:
val myColorString = "#B00020"
val myComposeColorInt = Color(myColorString.toColorInt())
How about solution not dependant on Android? #KMP
val hashColorString = "#00AB18"
val color = Color(hashColorString.removePrefix("#").toLong(16) or 0x00000000FF000000)
hex string to color [this extension function is available inside android sdk
]
Color("#FFFFFF".toColorInt())
incase if u want to convert back to hex code
fun Color.toHexCode(): String {
val red = this.red * 255
val green = this.green * 255
val blue = this.blue * 255
return String.format("#%02x%02x%02x", red.toInt(), green.toInt(), blue.toInt())
}
incase if u also want alpha value
fun Color.toHexCodeWithAlpha(): String {
val alpha = this.alpha*255
val red = this.red * 255
val green = this.green * 255
val blue = this.blue * 255
return String.format("#%02x%02x%02x%02x", alpha.toInt(),red.toInt(), green.toInt(), blue.toInt())
}
If you want to avoid having to import android.graphics.Color, here's another straightforward alternative:
val hexString = "#f8f8f2"
Color(("ff" + hexString.removePrefix("#").lowercase()).toLong(16))
Color in this case would be immediately the one from androidx.compose.ui.graphics.Color.

Android ViewPager2 setPageMargin unresolved

I want to implement Carousel using View Pager2 with preview of left and right page like this:
Initially I was using view pager1 which supported. Now I think it's removed
viewPagerhost.setPageMargin(20);
Any idea how we can achieve this using View Pager 2
MarginPageTransformer cannot help your need.
You must use custom setPageTrarnsformer.
Step 1
Here is my Extension Method for this.
you can check detail in this article
Medium article
fun ViewPager2.setShowSideItems(pageMarginPx : Int, offsetPx : Int) {
clipToPadding = false
clipChildren = false
offscreenPageLimit = 3
setPageTransformer { page, position ->
val offset = position * -(2 * offsetPx + pageMarginPx)
if (this.orientation == ViewPager2.ORIENTATION_HORIZONTAL) {
if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
page.translationX = -offset
} else {
page.translationX = offset
}
} else {
page.translationY = offset
}
}
}
Step 2
set pageMarginPx and offsetPx with your use case.
<resources>
<dimen name="pageMargin">20dp</dimen>
<dimen name="pagerOffset">30dp</dimen>
<dimen name="pageMarginAndoffset">50dp</dimen>
</resources>
Step 3
set your side margin of layout item in your xml.
like this
<androidx.cardview.widget.CardView
app:cardCornerRadius="12dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:layout_marginLeft="#dimen/pageMarginAndoffset"
android:layout_marginRight="#dimen/pageMarginAndoffset"
android:layout_width="match_parent"
android:layout_height="match_parent">
Now we need to use setPageTransformer() in Version 1.0.0-alpha05
New features
ItemDecorator introduced with a behaviour consistent with RecyclerView.
MarginPageTransformer introduced to provide an ability to create space between pages (outside of page inset).
CompositePageTransformer introduced to provide an ability to combine multiple PageTransformers.
SAMPLE CODE
myViewPager2.setPageTransformer(new MarginPageTransformer(1500));
Check out my previous answer if you want to implement Carousel using View Pager2
I used MJ Studio's approach to create my custom PageTransformer that also changes the page margin as follows:
class OffsetPageTransformer(
#Px private val offsetPx: Int,
#Px private val pageMarginPx: Int
) : ViewPager2.PageTransformer {
override fun transformPage(page: View, position: Float) {
val viewPager = requireViewPager(page)
val offset = position * -(2 * offsetPx + pageMarginPx)
val totalMargin = offsetPx + pageMarginPx
if (viewPager.orientation == ViewPager2.ORIENTATION_HORIZONTAL) {
page.updateLayoutParams<ViewGroup.MarginLayoutParams> {
marginStart = totalMargin
marginEnd = totalMargin
}
page.translationX = if (ViewCompat.getLayoutDirection(viewPager) == ViewCompat.LAYOUT_DIRECTION_RTL) {
-offset
} else {
offset
}
} else {
page.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = totalMargin
bottomMargin = totalMargin
}
page.translationY = offset
}
}
private fun requireViewPager(page: View): ViewPager2 {
val parent = page.parent
val parentParent = parent.parent
if (parent is RecyclerView && parentParent is ViewPager2) {
return parentParent
}
throw IllegalStateException(
"Expected the page view to be managed by a ViewPager2 instance."
)
}
}
That way you can just call:
viewPager.setPageTransformer(OffsetPageTransformer(offsetPx, pageMarginPx))
you can use this code
viewPager.setPageTransformer(new MarginPageTransformer(margin as PX));
but if you want to use DP you can use the below function for convert PX to DP
private int pxToDp(int px) {
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
MarginPageTransformer helps to define spaces between pages.
offscreenPageLimit let you define how many pages should be rendered offscreen.
Sample of the code:
viewPager2.offscreenPageLimit = 3
viewPager2.setPageTransformer(MarginPageTransformer({MARGIN AS PX}));

Change CardBackgroundColor on RecyclerView

I have the following code on my RecyclerView:
class TaskViewHolder(v: View) : RecyclerView.ViewHolder(v), View.OnClickListener
{
var mId: TextView = v.task_id
var mDescription: TextView = v.task_description
var mCard: CardView = v.task_card
var mView: View = v
}
override fun onBindViewHolder(holder: TaskViewHolder, position: Int)
{
// Initialize ViewHolder content
holder.mId.text = items[position].getID().toString()
holder.mDescription.text = items[position].getDescription()
holder.mTask = items[position]
for (elem in priorities)
{
if (elem.getID() == items[position].getPriority())
{
holder.mCard.setCardBackgroundColor(Color.parseColor("#c2c2c2"))
break
}
}
}
I don't know why, but CardView backgroundColor isn't changing.
If I use the following code, it works correctly:
holder.mCard.setCardBackgroundColor(ContextCompat.getColor(holder.mView.context, R.color.priority3))
What I should do to set CardBackgroundColor progrmatically?
First of all, You need to provide else part as transparent or another color to avoid color duplicate render issue. second, you have to pass context from your activity or fragment to adapter and that context will be used to get color like below.
if (elem.getID() == items[position].getPriority())
{
holder.mCard.setCardBackgroundColor(ContextCompat.getColor(mContext, [first color]))
} else {
holder.mCard.setCardBackgroundColor(ContextCompat.getColor(mContext,[second color]))
}
Try replacing "#c2c2c2" with "#ffc2c2c2" to make sure you provide a correct alpha for the background colour. On android, this extra byte added at the beginning represents the alpha of the colour:
#ffc2c2c2
ff: alpha
c2: red
c2: green
c2: blue

Manage Screen Display and Bottom button when keyboard open and hide in iOS same as Android

Expected Functionality is the same as it happens in Android devices (Check below Images):
When Keyboard opens, the bottom button is animated to up and also the screen shifted a little upwards, depending on the Device Screen size. Check below Image
I am trying to implement the same functionality in my iOS Application.
Here is my code:
#objc func keyboardWillChangeFrame(_ notification: Notification?) {
guard let keyboardRect = (notification?.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {return}
let screenY = UIScreen.main.bounds.height
let shrunkViewHeight = screenY - keyboardRect.height
self.forwardButton.frame.origin.y = keyboardRect.origin.y
if (shrunkViewHeight < screenY/1.5) {
let screenShift = ((screenY/2) - shrunkViewHeight)
if notification?.name == UIResponder.keyboardWillShowNotification || notification?.name == UIResponder.keyboardWillChangeFrameNotification {
UIView.animate(withDuration: 1.0) {
self.view.frame.origin.y = screenShift
}
}else{
UIView.animate(withDuration: 1.0) {
self.view.frame.origin.y = 0
}
}
}
}
What is Happening presently:
The button sometimes remains at the bottom especially when the first responder changes from one TextField to another without closing the keyboard.
Solution Expected: The mentioned functionality should work for all iPhones ranging from iPhone 6 to latest XR. Open to the third party suggestions.
Swift 3
#IBOutlet weak var BottomConstraint: NSLayoutConstraint! //your last item in bottom of your view controller constraint
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.registerForKeyboardNotifications()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.deregisterFromKeyboardNotifications()
}
func registerForKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardNotification(_:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}
func deregisterFromKeyboardNotifications() {
NotificationCenter.default.removeObserver(self)
}
func keyboardNotification(_ notification: Foundation.Notification) {
if let userInfo = notification.userInfo {
let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions().rawValue
let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
if (endFrame?.origin.y)! >= UIScreen.main.bounds.size.height {
self.sendCmntViewBottomConstraint?.constant = 0.0
} else {
self.sendCmntViewBottomConstraint?.constant = endFrame!.size.height
}
UIView.animate(withDuration: duration, delay: TimeInterval(0), options: animationCurve, animations: { self.view.layoutIfNeeded() }, completion: nil)
}
}
Swift 4
#IBOutlet weak var BottomConstraint: NSLayoutConstraint! //your last item in bottom of your view controller constraint
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.registerForKeyboardNotifications()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.deregisterFromKeyboardNotifications()
}
func registerForKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardNotification(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
func deregisterFromKeyboardNotifications() {
NotificationCenter.default.removeObserver(self)
}
#objc func keyboardNotification(_ notification: Foundation.Notification) {
if let userInfo = notification.userInfo {
let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
let duration:TimeInterval = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions().rawValue
let animationCurve:UIView.AnimationOptions = UIView.AnimationOptions(rawValue: animationCurveRaw)
if (endFrame?.origin.y)! >= UIScreen.main.bounds.size.height {
self.requestBttnButtomMargin?.constant = 24.0
} else {
self.requestBttnButtomMargin?.constant = endFrame!.size.height + 10
}
UIView.animate(withDuration: duration,
delay: TimeInterval(0),
options: animationCurve,
animations: { self.view.layoutIfNeeded() },
completion: nil)
}
}
}
A few points:
1. Your code sample doesn’t show it, but it seems as though you are sending all notifications via this method. I recommend handling willView and willHide separately. You may not need to subscribe to didChangeFrame.
What is the shrunkViewHeight < screenY/1.5 check for? It will always return false on any sizeable device.
UIScreen usage here is dangerous, particularly for iPad or landscape supporting apps. Check against view.frame instead.
Are you using auto layout? In this case, look into handling the change by changing a constraint.
Here is a code sample for willShow that should help you on your way:
var viewFrame = view.frame
viewFrame.size.height -= keyboardRect.height
if viewFrame.contains(forwardButton.frame) {
return // Do nothing, button is visible
}
// Modify your button frame here

Categories

Resources