How to Create a Button Programmatically

Make a UIButton programmatically in Swift

You're just missing the colon at the end of the selector name. Since pressed takes a parameter the colon must be there. Also your pressed function shouldn't be nested inside viewDidLoad.

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let myFirstLabel = UILabel()
let myFirstButton = UIButton()
myFirstLabel.text = "I made a label on the screen #toogood4you"
myFirstLabel.font = UIFont(name: "MarkerFelt-Thin", size: 45)
myFirstLabel.textColor = .red
myFirstLabel.textAlignment = .center
myFirstLabel.numberOfLines = 5
myFirstLabel.frame = CGRect(x: 15, y: 54, width: 300, height: 500)
myFirstButton.setTitle("✸", for: .normal)
myFirstButton.setTitleColor(.blue, for: .normal)
myFirstButton.frame = CGRect(x: 15, y: -50, width: 300, height: 500)
myFirstButton.addTarget(self, action: #selector(pressed), for: .touchUpInside)
}

@objc func pressed() {
var alertView = UIAlertView()
alertView.addButtonWithTitle("Ok")
alertView.title = "title"
alertView.message = "message"
alertView.show()
}

EDIT: Updated to reflect best practices in Swift 2.2. #selector() should be used rather than a literal string which is deprecated.

How can I create a button programmatically in C# window app?

As you said it is Winforms, you can do the following...

First create a new Button object.

Button newButton = new Button();

Then add it to the form inside that function using:

this.Controls.Add(newButton);

Extra properties you can set...

newButton.Text = "Created Button";
newButton.Location = new Point(70,70);
newButton.Size = new Size(50, 100);

Your issue you're running to is that you're trying to set it on Form_Load event, at that stage the form does not exist yet and your buttons are overwritten. You need a delegate for the Shown or Activated events in order to show the button.

For example inside your Form1 constructor,

public Form1()
{
InitializeComponent();
this.Shown += CreateButtonDelegate;
}

Your actual delegate is where you create your button and add it to the form, something like this will work.

private void CreateButtonDelegate(object sender, EventArgs e)
{
Button newButton= new Button();
this.Controls.Add(newButton);
newButton.Text = "Created Button";
newButton.Location = new Point(70,70);
newButton.Size = new Size(50, 100);
newButton.Location = new Point(20, 50);
}

How do I create a basic UIButton programmatically?

Here's one:

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:@selector(aMethod:)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"Show View" forState:UIControlStateNormal];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[view addSubview:button];

Adding button programmatically swift

Change with

playPauseButton.addTarget(self, action: #selector(playAction), for: .touchUpInside)

this is ok:

@objc
func playAction(sender: UIButton) {
print("Hello")
}

works for me

How to create a button programmatically with for loop in swift

Various ways to do that...

  1. find the frame of the tapped button (not a good approach, but for your simple example it could work)
  2. use the .tag property of the button
  3. evaluate the .currentTitle property of the button
  4. add the buttons to an array... on tap, use let buttonNumber = btnsArray.firstIndex(of: sender)

How to create a UIButton programmatically

You're just missing which UIButton this is. To compensate for this, change its tag property.

Here is you answer:

let btn: UIButton = UIButton(frame: CGRectMake(100, 400, 100, 50))
btn.backgroundColor = UIColor.greenColor()
btn.setTitle("Click Me", forState: UIControlState.Normal)
btn.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
btn.tag = 1 // change tag property
self.view.addSubview(btn) // add to view as subview

Swift 3.0

let btn: UIButton = UIButton(frame: CGRect(x: 100, y: 400, width: 100, height: 50))
btn.backgroundColor = UIColor.green
btn.setTitle(title: "Click Me", for: .normal)
btn.addTarget(self, action: #selector(buttonAction), forControlEvents: .touchUpInside)
btn.tag = 1
self.view.addSubview(btn)

Here is an example selector function:

func buttonAction(sender: UIButton!) {
var btnsendtag: UIButton = sender
if btnsendtag.tag == 1 {
//do anything here
}
}

How to create an IBAction for a button programmatically-created based on user input

use addTarget to bind an action to a method

func buttonClicked(sender: UIButton){
print("button Clicked")
}

then add target to button

var button = UIButton()
button.addTarget(self, action: #selector(self.buttonClicked(sender:)), for: .touchUpInside)

How to create a selector for a Button programmatically

You will need to recreate the following drawable programmatically:

<selector>
<item android:drawable="@android:color/holo_blue_light" android:state_pressed="true" />
<item>
<inset android:drawable="@android:color/holo_red_light" android:inset="12.5%" />
</item>
</selector>

This StateListDrawable uses an InsetDrawable to set the background color to something smaller than the view width and height.

In the following layout

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/darker_gray">

<View
android:layout_width="300dp"
android:layout_height="300dp"
android:background="@android:color/holo_green_light"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<ImageButton
android:id="@+id/imageButton"
android:layout_width="300dp"
android:layout_height="300dp"
android:background="@drawable/selector_drawable"
android:src="@drawable/ic_launcher_foreground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

the background behaves as follows:

Sample Image

The green square is there just to show the true extent of the ImageButton.

Here is the code to create the StateListDrawable programmatically and to assign it to the ImageButton:

val blue = ContextCompat.getColor(requireContext(), android.R.color.holo_blue_light)  
val red = ContextCompat.getColor(requireContext(), android.R.color.holo_red_light)

// Create the inset drawable that is inset 12.5% on each side. This will be the default state.
val colorDrawable = ColorDrawable(red)
val insetDrawable = InsetDrawable(colorDrawable, 0.12f)

// Create the drawable that will be the pressed state background.
val pressedStateDrawable = ColorDrawable(blue)
val bg = StateListDrawable()
bg.addState(intArrayOf(android.R.attr.state_pressed), pressedStateDrawable)
bg.addState(intArrayOf(), insetDrawable)
binding.imageButton.background = bg



If you want to animate the background, you can use a ScaleDrawable with a ValueAnimator. Here is some sample code:

val baseLevel = 7500
val topLevel = 10000
val animationDuration = 250L
val redColor = ContextCompat.getColor(requireContext(), android.R.color.holo_red_light)
val colorDrawable = ColorDrawable(redColor)
val blueColor = ContextCompat.getColor(requireContext(), android.R.color.holo_blue_light)
val scaleDrawable = ScaleDrawable(colorDrawable, Gravity.CENTER, 1f, 1f)
scaleDrawable.level = baseLevel
binding.imageButton.background = scaleDrawable
binding.imageButton.setOnClickListener {
ValueAnimator.ofInt(baseLevel, topLevel).apply {
duration = animationDuration
doOnStart {
(scaleDrawable.drawable as ColorDrawable).color = blueColor
scaleDrawable.level = baseLevel
}
addUpdateListener {
scaleDrawable.level = it.animatedValue as Int
binding.imageButton.invalidate()
}
doOnEnd {
(scaleDrawable.drawable as ColorDrawable).color = redColor
scaleDrawable.level = baseLevel
}
start()
}
}

Sample Image




A still better way (IMO) is to encapsulate the expanding drawable as a custom drawable.

ExpandingBackgroundDrawable.kt

class ExpandingBackgroundDrawable(
matchStates: IntArray,
activeColor: Int,
insetPercentage: Float,
animationDuration: Long
) : Drawable(), Animatable, TimeAnimator.TimeListener {

private val mMatchStates = matchStates
private val mInsetPercentage = insetPercentage
private val mAnimDuration = animationDuration

private var mRunning = false
private var mStartTime = 0L
private val mTimeAnimator: TimeAnimator = TimeAnimator().also {
it.setTimeListener(this)
}

private var mPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = activeColor
style = Paint.Style.FILL
}

private val mRectMin = RectF()
private val mRectCurrent = RectF()

// Notify this Drawable when the View's state changes.
override fun isStateful() = true

override fun onStateChange(states: IntArray): Boolean {
return if (StateSet.stateSetMatches(mMatchStates, states)) {
start()
true
} else {
false
}
}

override fun onBoundsChange(bounds: Rect) {
super.onBoundsChange(bounds)
mRectMin.set(
0f, 0f, bounds.right - mInsetPercentage * bounds.right * 2,
bounds.bottom - mInsetPercentage * bounds.bottom * 2
)
}

override fun draw(canvas: Canvas) {
canvas.withTranslation(
(bounds.width() - mRectCurrent.right) / 2,
(bounds.height() - mRectCurrent.bottom) / 2
) {
canvas.drawRect(mRectCurrent, mPaint)
}
}

override fun setAlpha(alpha: Int) {
mPaint.alpha = alpha
}

override fun setColorFilter(colorFilter: ColorFilter?) {
mPaint.colorFilter = colorFilter
}

override fun getOpacity() = PixelFormat.TRANSLUCENT

override fun start() {
if (isRunning) return
mRunning = true
mStartTime = SystemClock.uptimeMillis()
invalidateSelf()
mTimeAnimator.duration = mAnimDuration
mTimeAnimator.start()
}

override fun stop() {
if (!isRunning) return
mTimeAnimator.cancel()
mRunning = false
invalidateSelf()
}

override fun isRunning() = mRunning

override fun onTimeUpdate(animation: TimeAnimator, totalTime: Long, deltaTime: Long) {
val progress = totalTime.toFloat() / animation.duration
mRectCurrent.right = mRectMin.right + (bounds.right - mRectMin.right) * progress
mRectCurrent.bottom = mRectMin.bottom + (bounds.bottom - mRectMin.bottom) * progress
if (progress >= 1F) {
stop()
} else {
invalidateSelf()
}
}

fun setColor(color: Int) {
mPaint.color = color
invalidateSelf()
}
}

The custom drawable would be created as follows:

imageButton.background = getBackground(context)

private fun getBackground(view: View): Drawable {
val context = view.context

// Create the inset drawable that is inset 12.5% on each side.
// This will be the default state.
val red = ContextCompat.getColor(context, android.R.color.holo_red_light)
val colorDrawable = ColorDrawable(red)
val insetDrawable = InsetDrawable(colorDrawable, 0.125f)

// Get the expanding background drawable that is the pressed state drawable.
val expandingStates = intArrayOf(
android.R.attr.state_pressed,
android.R.attr.state_accelerated
)
val mExpandingBackground = ExpandingBackgroundDrawable(
expandingStates,
ContextCompat.getColor(context, R.color.accent),
0.125f,
context.resources.getInteger(android.R.integer.config_shortAnimTime).toLong()
)

return StateListDrawable().apply {
addState(expandingStates, mExpandingBackground)
addState(StateSet.WILD_CARD, insetDrawable)
}
}

While the state of the ImageButton is "pressed", the background will start as the size of the InsetDrawable and expand to the size of the outer square. When the "pressed" state is removed, the drawable will disappear.

Android - Create Button Programmatically

Creating custom Views does not prevent you from having XML layouts. For example:

<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.yourpackage.GameLoopLayout
android:id="@+id/game_loop_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
... />

</FrameLayout>

You can use margins and android:layout_gravity to place the button wherever you like.

In code, get access to your GameLoopLayout like you would any other view:

// inside of onCreate()
mGameLoopLayout = (GameLoopLayout) findViewById(R.id.game_loop_layout);
// do setup with GameLoopLayout


Related Topics



Leave a reply



Submit