Creating button with CoreGraphics in monotouch - xamarin.ios

I am trying to create a button with CoreGraphics on monotouch. I can't figure out how to change the buttons color when its pushed. I tried overriding the TouchesBegan and TouchesEnded methods but I can't figure out how to change the color.

You could handle the background color two ways. You can simply set the BackgroundColor property. This should automatically change the color. Or if you are storing the color as a private variable to be used for FillRect, you need to call SetNeedsDisplay to force a call to Draw.
public override void TouchesBegan (MonoTouch.Foundation.NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
this.BackgroundColor = UIColor.Green;
backColor2 = UIColor.Yellow;
this.SetNeedsDisplay ();
}
public override void TouchesEnded (MonoTouch.Foundation.NSSet touches, UIEvent evt)
{
base.TouchesEnded (touches, evt);
this.BackgroundColor = UIColor.Red;
backColor2 = UIColor.Blue;
this.SetNeedsDisplay ();
}
public override void Draw (RectangleF rect)
{
base.Draw (rect);
using (CGContext context = UIGraphics.GetCurrentContext ()) {
RectangleF rect2 = this.Bounds;
rect2.X += 10;
rect2.Y += 5;
rect2.Width -= 20;
rect2.Height -= 10;
backColor2.SetFill ();
context.FillRect (rect2);
}
}

Related

Xamarin iOS: How to hide seek bar in AvPlayer?

I'm building an app in xamarin ios using AvPlayer. How can I hide the seek bar ?
_playerViewController = new CustomAVPlayerViewController();
_player = new AVPlayer();
_playerViewController.Player = _player;
SetNativeControl(_playerViewController.View);
public class CustomAVPlayerViewController: AVPlayerViewController
{
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
}
}
If you don't want to show the controls or want to highly customize the appearance, I recommend you to use AVPlayerLayer:
public class CustomPlayerRenderer : ViewRenderer<CustomPlayer, UIView>
{
AVPlayer _player;
AVPlayerLayer _playerLayer;
protected override void OnElementChanged(ElementChangedEventArgs<CustomPlayer1> e)
{
base.OnElementChanged(e);
if (Control == null)
{
_player = new AVPlayer(new NSUrl(NSBundle.MainBundle.PathForResource("sample.mp4", null), false));
_playerLayer = AVPlayerLayer.FromPlayer(_player);
UIView view = new UIView();
view.Layer.AddSublayer(_playerLayer);
SetNativeControl(view);
//_player.Play();
// Add custom controls as you want on this view
}
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
_playerLayer.Frame = rect;
}
}

Vertical ProgressBar JavaFX

I have a StackPane with the size of (15px width, 400px height). I want to but a "Vertical ProgressBar" to that StackPane. What I was doing is to rotate the progressbar by 90 degree. However, the progressBar cannot fit in the stackpane with that rotation. It just shows as a small squared progressbar at the center of StackPane.
How can I fixed that?
Sample vertical progress bar.
class UpwardProgress {
private ProgressBar progressBar = new ProgressBar();
private Group progressHolder = new Group(progressBar);
public UpwardProgress(double width, double height) {
progressBar.setMinSize(StackPane.USE_PREF_SIZE, StackPane.USE_PREF_SIZE);
progressBar.setPrefSize(height, width);
progressBar.setMaxSize(StackPane.USE_PREF_SIZE, StackPane.USE_PREF_SIZE);
progressBar.getTransforms().setAll(
new Translate(0, height),
new Rotate(-90, 0, 0)
);
}
public ProgressBar getProgressBar() {
return progressBar;
}
public Group getProgressHolder() {
return progressHolder;
}
}
Used in a sample app.
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.scene.*;
import javafx.scene.canvas.*;
import javafx.scene.control.*;
import javafx.scene.image.PixelWriter;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.transform.*;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.Random;
class UpwardProgress {
private ProgressBar progressBar = new ProgressBar();
private Group progressHolder = new Group(progressBar);
public UpwardProgress(double width, double height) {
progressBar.setMinSize(StackPane.USE_PREF_SIZE, StackPane.USE_PREF_SIZE);
progressBar.setPrefSize(height, width);
progressBar.setMaxSize(StackPane.USE_PREF_SIZE, StackPane.USE_PREF_SIZE);
progressBar.getTransforms().setAll(
new Translate(0, height),
new Rotate(-90, 0, 0)
);
}
public ProgressBar getProgressBar() {
return progressBar;
}
public Group getProgressHolder() {
return progressHolder;
}
}
public class StarCounter extends Application {
public static final Color INDIA_INK = Color.rgb(35, 39, 50);
private static final int CANVAS_SIZE = 400;
private static final int N_STARS = 1_000;
private final Canvas canvas = new Canvas(CANVAS_SIZE, CANVAS_SIZE);
private final Random random = new Random(42);
private final IntegerProperty visibleStars = new SimpleIntegerProperty(0);
private Timeline timeline;
#Override
public void start(final Stage stage) {
Group root = initProgress();
clearCanvas();
visibleStars.addListener((observable, oldValue, newValue) -> {
if (newValue.intValue() > oldValue.intValue()) {
addStars(newValue.intValue() - oldValue.intValue());
}
});
stage.setScene(
new Scene(
new HBox(canvas, root),
INDIA_INK
)
);
stage.show();
runSimulation();
stage.getScene().setOnMouseClicked(event -> {
resetSimulation();
runSimulation();
});
}
private Group initProgress() {
UpwardProgress upwardProgress = new UpwardProgress(15, 400);
ProgressIndicator bar = upwardProgress.getProgressBar();
bar.setStyle("-fx-base: skyblue; -fx-accent: gold;");
bar.progressProperty().bind(visibleStars.divide(N_STARS * 1.0));
return upwardProgress.getProgressHolder();
}
private void resetSimulation() {
clearCanvas();
if (timeline != null) {
timeline.stop();
timeline = null;
}
}
private void runSimulation() {
timeline = new Timeline(
new KeyFrame(
Duration.seconds(0),
new KeyValue(visibleStars, 0)
),
new KeyFrame(
Duration.seconds(10),
new KeyValue(visibleStars, N_STARS)
)
);
timeline.play();
}
private void clearCanvas() {
canvas.getGraphicsContext2D().setFill(INDIA_INK);
canvas.getGraphicsContext2D().fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);
}
private void addStars(int nStarsToAdd) {
GraphicsContext context = canvas.getGraphicsContext2D();
PixelWriter writer = context.getPixelWriter();
for (int i = 0; i < nStarsToAdd; i++) {
writer.setColor(random.nextInt(CANVAS_SIZE), random.nextInt(CANVAS_SIZE), Color.GOLD);
}
}
public static void main(String[] args) {
launch(args);
}
}
There's another alternative to this, which is, to make your own custom vertical progress-bar. Sounds too much but isn't. The advantage of this approach is that this is more consistent in UI and more dynamically approachable. I used the above answer by #jewel but struggled with UI consistency and dynamic behavior of the progress-bar.
The approach being use a vbox for the progress-bar and inside it another vbox for bar.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.device.ui.VerticalProgressBarController">
<children>
<VBox fx:id="progress_bar" alignment="BOTTOM_CENTER" prefHeight="450.0" prefWidth="20.0" style="-fx-border-color: black; -fx-border-radius: 2 2 2 2;">
<children>
<VBox fx:id="bar" prefHeight="0.0" prefWidth="20.0" style="-fx-border-radius: 2 2 2 2;"/>
</children>
</VBox>
</children>
</VBox>
One can adjust the prefHeight of progress-bar and bar dynamically in controller or statically in .fxml file. Since here, only bar was the one I needed to adjust dynamically, so have set its prefHeight as 0 and adjust it appropriately in corresponding controller.
public class VerticalProgressBarController implements Initializable {
#FXML
VBox progress_bar;
#FXML
VBox bar;
private double progress_bar,fixed_capacity;
public void initialize(URL location, ResourceBundle resources) {
progressBarHeight = progress_bar.getPrefHeight();
bar.setMaxHeight(progressBarHeight);
// initial bar color
setGreenBar();
// set the max capacity of the progress bar
fixed_capacity = 100;
// pass in the proportion; here wanted to show 15 on a scale of 100
updateProgressBar(15 / fixed_capacity);
}
public void setGreenBar(){
bar.setStyle("-fx-background-color: green");
}
public void setYellowBar(){
bar.setStyle("-fx-background-color: yellow");
}
public void setRedBar(){
bar.setStyle("-fx-background-color: red");
}
public void updateProgressBar(double progress){
bar.setPrefHeight(progressBarHeight * progress);
if(progress <= .60){
setGreenBar();
} else if(progress > .60 &&
progress <= .75){
setYellowBar();
}else {
setRedBar();
}
}

Internal Frames in JavaFX

I found this example of Internal Frames
http://docs.oracle.com/javase/tutorial/uiswing/components/internalframe.html
Is it possible to make the same internal Frames in JavaFX?
With JFXtras there is a Window control, where you can add content and handle the internal window behavior.
First you will need to put in your classpath the jfxtras library. They have some instructions where you can get the library. If you are using maven, just need to add:
<dependency>
<groupId>org.jfxtras</groupId>
<artifactId>jfxtras-labs</artifactId>
<version>2.2-r5</version>
</dependency>
Or download the library and put it into your project classpath, whatever.
Now I put a sample of the demo of the Window with a little difference, allowing generation of several windows.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import jfxtras.labs.scene.control.window.CloseIcon;
import jfxtras.labs.scene.control.window.MinimizeIcon;
import jfxtras.labs.scene.control.window.Window;
public class WindowTests extends Application {
private static int counter = 1;
private void init(Stage primaryStage) {
final Group root = new Group();
Button button = new Button("Add more windows");
root.getChildren().addAll(button);
primaryStage.setResizable(false);
primaryStage.setScene(new Scene(root, 600, 500));
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
// create a window with title "My Window"
Window w = new Window("My Window#"+counter);
// set the window position to 10,10 (coordinates inside canvas)
w.setLayoutX(10);
w.setLayoutY(10);
// define the initial window size
w.setPrefSize(300, 200);
// either to the left
w.getLeftIcons().add(new CloseIcon(w));
// .. or to the right
w.getRightIcons().add(new MinimizeIcon(w));
// add some content
w.getContentPane().getChildren().add(new Label("Content... \nof the window#"+counter++));
// add the window to the canvas
root.getChildren().add(w);
}
});
}
public double getSampleWidth() {return 600;}
public double getSampleHeight() {return 500;}
#Override
public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args) {launch(args);}
}
In the original demo, the event code was in the init method, and no button was included. I add the button to create dynamically windows and adding them to the screen.
Here is a snapshot of the result of the application:
I totally recommend you try the demo of jfxtras. They have really great stuff. Hope it helps.
You can implement simple internal window themselves. Main idea, that InternalWindow class just skeleton, that has internal frame like functionality. You can apply any content to it.
1) Declare class
public class InternalWindow extends Region
2) You should be able to set content in window
public void setRoot(Node node) {
getChildren().add(node);
}
3) You should be able to bring window to front if many window exist
public void makeFocusable() {
this.setOnMouseClicked(mouseEvent -> {
toFront();
});
}
4) Now we need dragging functionality
//just for encapsulation
private static class Delta {
double x, y;
}
//we can select nodes that react drag event
public void makeDragable(Node what) {
final Delta dragDelta = new Delta();
what.setOnMousePressed(mouseEvent -> {
dragDelta.x = getLayoutX() - mouseEvent.getScreenX();
dragDelta.y = getLayoutY() - mouseEvent.getScreenY();
//also bring to front when moving
toFront();
});
what.setOnMouseDragged(mouseEvent -> {
setLayoutX(mouseEvent.getScreenX() + dragDelta.x);
setLayoutY(mouseEvent.getScreenY() + dragDelta.y);
});
}
5) Also we want able to resize window (I show only simple right-bottom resizing)
//current state
private boolean RESIZE_BOTTOM;
private boolean RESIZE_RIGHT;
public void makeResizable(double mouseBorderWidth) {
this.setOnMouseMoved(mouseEvent -> {
//local window's coordiantes
double mouseX = mouseEvent.getX();
double mouseY = mouseEvent.getY();
//window size
double width = this.boundsInLocalProperty().get().getWidth();
double height = this.boundsInLocalProperty().get().getHeight();
//if we on the edge, change state and cursor
if (Math.abs(mouseX - width) < mouseBorderWidth
&& Math.abs(mouseY - height) < mouseBorderWidth) {
RESIZE_RIGHT = true;
RESIZE_BOTTOM = true;
this.setCursor(Cursor.NW_RESIZE);
} else {
RESIZE_BOTTOM = false;
RESIZE_RIGHT = false;
this.setCursor(Cursor.DEFAULT);
}
});
this.setOnMouseDragged(mouseEvent -> {
//resize root
Region region = (Region) getChildren().get(0);
//resize logic depends on state
if (RESIZE_BOTTOM && RESIZE_RIGHT) {
region.setPrefSize(mouseEvent.getX(), mouseEvent.getY());
} else if (RESIZE_RIGHT) {
region.setPrefWidth(mouseEvent.getX());
} else if (RESIZE_BOTTOM) {
region.setPrefHeight(mouseEvent.getY());
}
});
}
6) Usage. First we construct all layout. Then apply it to InternalWindow.
private InternalWindow constructWindow() {
// content
ImageView imageView = new ImageView("https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Cheetah4.jpg/250px-Cheetah4.jpg");
// title bar
BorderPane titleBar = new BorderPane();
titleBar.setStyle("-fx-background-color: green; -fx-padding: 3");
Label label = new Label("header");
titleBar.setLeft(label);
Button closeButton = new Button("x");
titleBar.setRight(closeButton);
// title bat + content
BorderPane windowPane = new BorderPane();
windowPane.setStyle("-fx-border-width: 1; -fx-border-color: black");
windowPane.setTop(titleBar);
windowPane.setCenter(imageView);
//apply layout to InternalWindow
InternalWindow interalWindow = new InternalWindow();
interalWindow.setRoot(windowPane);
//drag only by title
interalWindow.makeDragable(titleBar);
interalWindow.makeDragable(label);
interalWindow.makeResizable(20);
interalWindow.makeFocusable();
return interalWindow;
}
7) And how add window to layout
#Override
public void start(Stage primaryStage) throws Exception {
Pane root = new Pane();
root.getChildren().add(constructWindow());
root.getChildren().add(constructWindow());
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
Result
Full code: gist
Upd about close button:
You can add method to InternalWindow
public void setCloseButton(Button btn) {
btn.setOnAction(event -> ((Pane) getParent()).getChildren().remove(this));
}
And when construct:
interalWindow.setCloseButton(closeButton);

UIAlertView color and background in monotouch

How can I change the color or/and the background of UIAlertView. Found examples in objective-c, dunno how to apply them in monotouch
This should get you started, you probably need to tweak the image frame a bit to get it correct relative to your background image.
public class FooAlertView : UIAlertView
{
UIImageView imageView;
public FooAlertView()
{
this.Title = "Alert!";
this.Message = "Puppies are cute...";
AddButton("OK!");
imageView = new UIImageView(UIImage.FromFile("Images/popover/popoverBg.png"));
}
public override void Draw(RectangleF rect)
{
base.Draw(rect);
foreach(var uiview in this.Subviews) {
if(uiview.GetType() == typeof(UIImageView)) {
uiview.RemoveFromSuperview();
this.AddSubview(imageView);
this.SendSubviewToBack(imageView);
}
}
}
}
NO need to add new sub view with image. You can replace existing image in image view.
public override void Draw(RectangleF rect)
{
base.Draw(rect);
foreach (var uiview in this.Subviews)
{
if (uiview.GetType() == typeof(UIImageView))
{
UIImageView imageView = uiview as UIImageView;
if (imageView != null) imageView.Image = UIImage.FromFile("Images/header.png");
}
}
}

LWUIT progress bar

I want to show a progress bar indicating loading application at the beginning.
How can that be done? I have created a gauge but I think it cannot be implemented in LWUIT form..
Based on my comment, You can use progress bar. And also you can use slider component for instead of showing progress bar in LWUIT.
The best way is to use canvas. You can reuse the class in all your apps and it is very efficient. Create a class, say like a class named Splash:
public class Splash extends Canvas {
private final int height;
private final int width;
private int current = 0;
private final int factor;
private final Timer timer = new Timer();
Image AppLogo;
MayApp MIDlet;
/**
*
* #param mainMIDlet
*/
public Splash(MyApp mainMIDlet) {
this.MIDlet = mainMIDlet;
setFullScreenMode(true);
height = getHeight();
width = this.getWidth();
factor = width / 110;
repaint();
timer.schedule(new draw(), 1000, 01);
}
/**
*
* #param g
*/
protected void paint(Graphics g) {
try {//if you want to show your app logo on the splash screen
AppLogo = javax.microedition.lcdui.Image.createImage("/appLogo.png");
} catch (IOException io) {
}
g.drawImage(AppLogo, getWidth() / 2, getHeight() / 2, javax.microedition.lcdui.Graphics.VCENTER | javax.microedition.lcdui.Graphics.HCENTER);
g.setColor(255, 255, 255);
g.setColor(128, 128, 0);//the color for the loading bar
g.fillRect(30, (height / 2) + 100, current, 6);//the thickness of the loading bar, make it thicker by changing 6 to a higher number and vice versa
}
private class draw extends TimerTask {
public void run() {
current = current + factor;
if (current > width - 60) {
timer.cancel();
try {
//go back to your midlet or do something
} catch (IOException ex) {
}
} else {
repaint();
}
Runtime.getRuntime().gc();//cleanup after yourself
}
}
}
and in your MIDlet:
public class MyApp extends MIDlet {
Splash splashScreen = new Splash(this);
public MyApp(){
}
public void startApp(){
try{
Display.init(this);
javax.microedition.lcdui.Display.getDisplay(this).setCurrent(splashScreen);
//and some more stuff
} catch (IOException ex){}
}
//continue

Resources