I tried to rotate the image by using matrix values and set the rotated bitmap to the image view. In this case, the image view background is set as black. Please provide any suggestions on this.
Device details: Motorola Moto G(4) (Android 7.0 - Api 24)
Sample:
My code:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
// Set our view from the "main" layout resource
LinearLayout linearLayout = new LinearLayout(this);
imageView = new ImageView(this);
imageView.LayoutParameters = new Android.Views.ViewGroup.LayoutParams(LinearLayout.LayoutParams.MatchParent, 1200);
bitmap = BitmapFactory.DecodeResource(Resources, Resource.Drawable.Nature);
linearLayout.AddView(imageView);
linearLayout.Orientation = Orientation.Vertical;
Button button = new Button(this);
button.Text = "Click me";
button.Click += Button_Click;
button.LayoutParameters = new Android.Views.ViewGroup.LayoutParams(150, 150);
linearLayout.AddView(button);
imageView.SetImageBitmap(bitmap);
SetContentView(linearLayout);
}
private void Button_Click(object sender, System.EventArgs e)
{
int angle = 45;
Matrix = new Matrix();
int cx = bitmap.Width / 2;
int cy = bitmap.Height / 2;
this.Matrix.PreTranslate(-cx, -cy);
this.Matrix.PostRotate(angle);
this.Matrix.PostTranslate(this.imageView.Width / 2, this.imageView.Height / 2);
using (var tiltBitmap = Bitmap.CreateBitmap(bitmap, 0, 0, bitmap.Width, bitmap.Height, Matrix, false))
{
imageView.SetImageBitmap(tiltBitmap);
}
this.Matrix.Dispose();
}
Related
I have this custom renderer where I want to resize the text to fit the button's bounding rect only if the text bounding box is greater than the button's.
What I'm trying to do is to draw the text "by hand" on top of the button's background without allowing the button itself to draw its text.
Is this possible without using a different type of view to fake a button?
Can I intercept somehow the FontSize property setter from the renderer, so I can store its value in some ivar while passing zero to the button so it won't draw the text?
public class AutoTextSizeButtonRenderer : ButtonRenderer
{
private float fontSize = 0;
private static float EPSILON = 0.1f;
public AutoTextSizeButtonRenderer(Context context) : base(context)
{
SetWillNotDraw(false);
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
Button button = Element as Button;
if (Math.Abs(button.FontSize - 1) > EPSILON && Math.Abs(button.FontSize - fontSize) > EPSILON) {
fontSize = (float)button.FontSize;
button.FontSize = 1;
}
//Draw(new Canvas());
}
public override void Draw(Canvas canvas)
{
base.Draw(canvas);
Button button = Element as Button;
string text = button.Text;
if (text != null)
{
TextPaint paint = new TextPaint();
//paint.SetTypeface(Typeface.DefaultBold);
paint.AntiAlias = true;
Rect bounds = new Rect();
Paint.FontMetrics metrics = null;
DisplayMetrics displayMetrics = new DisplayMetrics();
Display.GetMetrics(displayMetrics);
float scaledDensity = displayMetrics.ScaledDensity;
float textSize = fontSize;
while(textSize >= 0)
{
paint.TextSize = scaledDensity * textSize;
paint.GetTextBounds(text, 0, text.Length, bounds);
metrics = paint.GetFontMetrics();
if (bounds.Width() < MeasuredWidth && (metrics.Bottom - metrics.Top) < MeasuredHeight) {
break;
}
textSize--;
}
paint.Color = button.TextColor.ToAndroid();
canvas.DrawText(
text,
0.5f * MeasuredWidth - bounds.Left - 0.5f * bounds.Width(),
0.5f * MeasuredHeight - metrics.Ascent - 0.5f * (metrics.Bottom - metrics.Top),
paint);
}
}
}
how I did to detect changes in the value of FontSize in OnElementPropertyChanged
When you change your Xamarin.Forms.Button FontSize property, you could detect this change in the OnElementPropertyChanged method like this :
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Xamarin.Forms.Button.FontSizeProperty.PropertyName)
System.Diagnostics.Debug.WriteLine("FontSizeProperty has changed!");
}
Update :
Get the Button FontSize value :
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Xamarin.Forms.Button.FontSizeProperty.PropertyName)
System.Diagnostics.Debug.WriteLine("FontSizeProperty has changed!");
System.Diagnostics.Debug.WriteLine("Element.FontSize == " + Element.FontSize);
}
Im developing one app, In that app, Im sharing image in social networks(Converting the layout into image) so my question is in my layout am having share icon, so i want remove that share icon and add textview to that layout before converting into image. can anyone give solution for my question. Thanks in advance
final View itemView = inflater.inflate(R.layout.fragment_layout, container, false);
itemView.setDrawingCacheEnabled(true);
itemView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
itemView.layout(0, 0, 300, 400);
itemView.buildDrawingCache(true);
holder.share.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Bitmap bitmap = Bitmap.createBitmap(mView.getWidth(), mView.getHeight(), Bitmap.Config.ARGB_8888);
Bitmap bitmap = Bitmap.createBitmap(itemView.getWidth(),itemView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
itemView.draw(canvas);
Uri bmpUri = null;
try {
// output = new FileOutputStream(Environment.getExternalStorageDirectory() + "/path/to/file.png");
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS), "share_image_" + System.currentTimeMillis() + ".png");
file.getParentFile().mkdirs();
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
bmpUri = Uri.fromFile(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, bmpUri);
sendIntent.putExtra(Intent.EXTRA_TEXT, SplashScreen.newstitleArray.get(SplashScreen.myCustomPosition));
sendIntent.setType("image/*");
context1.startActivity(sendIntent);
}
});
I'd appreciate any help at all, I have spent hours at this to no avail.
So I need to add an instance of a class I found online called GridDisplay to the Parent root, as I need the scene to then display this for me. But I also need to use the fxml file to set up the root and hence the scene. Here is what I have so far:
#FXML private BorderPane mainPanel = new BorderPane();
#FXML private TilePane tilePane = new TilePane();
#FXML private Pane topCanvas = new Pane();
#FXML private Pane leftCanvas = new Pane();
#FXML private Pane rightCanvas = new Pane();
#FXML private Pane bottomCanvas = new Pane();
#FXML private ScrollPane scrollPane = new ScrollPane();
#FXML private Button stacksButton = new Button();
#FXML private Button queueButton = new Button();
#FXML private Button stepStacksButton = new Button();
#FXML private Button stepQueueButton = new Button();
private MazeSolver solver;
private GridDisplay gridDisplay;
private ArrayList<String> maze;
private String fileLocation;
private int height;
private int width;
#Override
public void start(Stage primaryStage) throws IOException, InterruptedException
{
solver = new MazeSolver(fileLocation);
int[] dimensions = solver.getDimensions();
this.width = dimensions[0];
this.height = dimensions[1];
maze = solver.getMazeLayout();
primaryStage.setTitle("Maze Solver");
//this is the root which uses the fxml file and in turn sets up the scene
Parent root = FXMLLoader.load(getClass().getResource("MazeApp.fxml"));
Scene scene = new Scene(root);
//Represents the grid with Rectangles
gridDisplay = new GridDisplay(height, width);
gridDisplay.setMaze(maze);
mainPanel = new BorderPane();
//here i set the scroll pane as the mainPanel's content
mainPanel.setCenter(scrollPane);
//and then set the gridDisplay as the scroll panes content
scrollPane.setContent(gridDisplay.getDisplay());
//re paints the grid and its boxes
gridDisplay.createElements();
primaryStage.setScene(scene);
primaryStage.show();
}
The order in which I do any of these things makes no difference, it just never shows. I am always left with the window and a blank space where the maze should be, like so: https://www.dropbox.com/s/rqxa9dy2w9lw4tz/Screenshot%202015-03-11%2022.01.46.png?dl=0 (sorry about linking, cant post image directly).
Any help would be greatly appreciated.
EDIT:
My GridDisplay class:
public class GridDisplay{
private static final double ELEMENT_SIZE = 30;
private static final double GAP = ELEMENT_SIZE / 90;
private TilePane tilePane = new TilePane();
private Group display = new Group(tilePane);
private int nRows;
private int nCols;
private ArrayList<String> maze = null;
public GridDisplay(int nRows, int nCols)
{
tilePane.setStyle("-fx-background-color: rgba(255, 215, 0, 0.1);");
tilePane.setHgap(GAP);
tilePane.setVgap(GAP);
setColumns(nCols);
setRows(nRows);
}
public void setColumns(int newColumns)
{
nCols = newColumns;
tilePane.setPrefColumns(nCols);
createElements();
}
public void setRows(int newRows)
{
nRows = newRows;
tilePane.setPrefRows(nRows);
createElements();
}
public TilePane getDisplay()
{
return tilePane;
}
public void createElements()
{
tilePane.getChildren().clear();
for (int i = 0; i < nRows; i++) {
for (int j = 0; j < nCols; j++) {
if(maze==null)
tilePane.getChildren().add(createElement(Color.RED));
else
{
Color color = Color.WHITE;
if(Character.toString(maze.get(i).charAt(j)).equals("#"))
color = Color.BLACK;
if(Character.toString(maze.get(i).charAt(j)).equals("o"))
color = Color.GREEN;
if(Character.toString(maze.get(i).charAt(j)).equals("*"))
color = Color.RED;
tilePane.getChildren().add(createElement(color));
}
}
}
}
public void colorSolved()
{
tilePane.getChildren().clear();
for (int i = 0; i < nRows; i++) {
for (int j = 0; j < nCols; j++) {
if(maze==null)
tilePane.getChildren().add(createElement(Color.RED));
else
{
Color color = Color.WHITE;
if(Character.toString(maze.get(i).charAt(j)).equals("#"))
color = Color.BLACK;
if(Character.toString(maze.get(i).charAt(j)).equals("o"))
color = Color.GREEN;
if(Character.toString(maze.get(i).charAt(j)).equals("*"))
color = Color.RED;
tilePane.getChildren().add(createElement(color));
}
}
}
}
public void setMaze(ArrayList<String> maze)
{
this.maze = maze;
}
private Rectangle createElement(Color color) {
Rectangle rectangle = new Rectangle(ELEMENT_SIZE, ELEMENT_SIZE);
rectangle.setStroke(Color.BLACK);
rectangle.setFill(color);
return rectangle;
}
}
I cannot share the code for the xml as it will not paste into this window properly, here is a picture:
https://www.dropbox.com/s/27tbliubdlqdfzm/Screenshot%202015-03-12%2010.09.25.png?dl=0
Since your root is a BorderPane, you can just set the appropriate region in the code:
BorderPane root = FXMLLoader.load(getClass().getResource("MazeApp.fxml"));
Scene scene = new Scene(root);
//Represents the grid with Rectangles
gridDisplay = new GridDisplay(height, width);
gridDisplay.setMaze(maze);
ScrollPane scrollPane = new ScrollPane();
scrollPane.setContent(gridDisplay);
root.setCenter(scrollPane);
// etc
I have shown on a 10-key layout dynamically created, now I need to retrieve the ID of the button pressed to release the necessary procedure. Here the code.
Button Btn;
Toast msg;
RelativeLayout rl;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
Btn = (Button) findViewById( R.id.Btntu );
for (int i = 0; i < 10; i++) {
Btn = new Button(this);
Btn.setText("Número: " + i);
Btn.setGravity(Gravity.CENTER);
Btn.setId(i);
rl = new RelativeLayout(this);
RelativeLayout.LayoutParams parametros = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
Btn.setLayoutParams(parametros);
rl.setLayoutParams(new LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT)
);
rl.addView(Btn);
ll.addView(rl);
}
I need the function to retrieve the ID of the button pressed.
Thank you all.
:o)
Have you tried getId() ?
http://developer.android.com/reference/android/view/View.html#getId%28%29
for (int i = 0; i < 10; i++) {
Btn = new Button(this);
Btn.setText("Número: " + i);
Btn.setGravity(Gravity.CENTER);
Btn.setId(i);
Btn.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
Log.d("Button", "ID clicked: " + Btn.getId());
// Or even
Log.d("View", "ID clicked: " + v.getId());
}
});
(...)
}
I can add SplitPane in a XYChart by clicking the "Add Pane" button, and it works fine.
Now I would like to remove SplitPane by clicking the "Remove pane" button.
Here is full code
public class SplitPaneFxTest extends Application {
SplitPane splitPane = new SplitPane();
double percSplit = 0.50;
int idxSplit = 0;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(SplitPaneFxTest.class, args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("SplitPane Test");
Group root = new Group();
Scene scene = new Scene(root, 800, 650, Color.WHITE);
//CREATE THE SPLITPANE
splitPane.setPrefSize(scene.getWidth(), scene.getHeight());
splitPane.setOrientation(Orientation.VERTICAL);
//ADD LAYOUTS AND ASSIGN CONTAINED CONTROLS
BorderPane upperPane = new BorderPane();
HBox hbox = new HBox();
Button button1 = new Button("Add Pane");
hbox.getChildren().addAll(button1);
upperPane.setTop(hbox);
Button button2 = new Button("Remove Pane");
hbox.getChildren().addAll(button2);
upperPane.setTop(hbox);
BorderPane lowerPane = new BorderPane();
splitPane.getItems().addAll(upperPane);
splitPane.setDividerPosition(idxSplit, 0.70);
idxSplit++;
splitPane.getItems().addAll(lowerPane);
idxSplit++;
root.getChildren().add(splitPane);
primaryStage.setScene(scene);
primaryStage.show();
button1.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
BorderPane myborderpane = new BorderPane();
splitPane.getItems().addAll(myborderpane);
ObservableList<SplitPane.Divider> splitDiv = splitPane.getDividers();
System.out.println("splitDiv.size() "+splitDiv.size());
percSplit = 1/(double)(splitDiv.size()+1);
for (int i = 0; i< splitDiv.size(); i++) {
System.out.println("i "+i+" percSplit "+percSplit);
splitPane.setDividerPosition(i, percSplit);
percSplit += 1/(double)(splitDiv.size()+1);
}
}
});
}
}
Any help really appreciated.
You can store a list of inner panes and remove them based on this list:
final List<Pane> panes = new ArrayList<Pane>();
button1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
BorderPane myborderpane = new BorderPane();
//adding
panes.add(myborderpane);
splitPane.getItems().addAll(myborderpane);
ObservableList<SplitPane.Divider> splitDiv = splitPane.getDividers();
System.out.println("splitDiv.size() " + splitDiv.size());
percSplit = 1 / (double) (splitDiv.size() + 1);
for (int i = 0; i < splitDiv.size(); i++) {
System.out.println("i " + i + " percSplit " + percSplit);
splitPane.setDividerPosition(i, percSplit);
percSplit += 1 / (double) (splitDiv.size() + 1);
}
}
});
button2.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
if (panes.size() > 0) {
// removing from both list and splitPane childs
Pane toDelete = panes.remove(0);
splitPane.getItems().remove(toDelete);
}
}
});
Also you can remove panes directly from ScrollPane.getChildren() but it can involve tricky and unreliable code to determine which pane to remove.