I have a problem. I need to adjust the font size of a text, so it fits inside the TextView. But how can I get the size of the TextView and the size of the Text to compare with each other?
If android api is above 8 , you can do that easily in axml:
<TextView
android:id="#+id/text"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:autoSizeMaxTextSize="80dp" //code one
android:autoSizeMinTextSize="2dp" // code two
android:autoSizeTextType="uniform" // code three
android:background="#android:color/holo_red_light"
android:gravity="center"
android:maxLines="1" // be sure not return line
android:text="Here is auto size text"
android:textColor="#android:color/white"
android:textSize="80dp" />
else you can refer to the follow code to custom a TextView:
using Android.Content;
using Android.Runtime;
using Android.Widget;
using Android.Util;
using Android.Text;
using Java.Lang;
namespace My.Text
{
public class AutoResizeTextView : TextView
{
public const float MIN_TEXT_SIZE = 20;
public interface OnTextResizeListener
{
void OnTextResize(TextView textView, float oldSize, float newSize);
}
private const string mEllipsis = "...";
private OnTextResizeListener mTextResizeListener;
private bool mNeedsResize = false;
private float mTextSize;
private float mMaxTextSize = 0;
private float mMinTextSize = MIN_TEXT_SIZE;
private float mSpacingMult = 1.0f;
private float mSpacingAdd = 0.0f;
public bool AddEllipsis { get; set; } = true;
public AutoResizeTextView(Context context) : this(context, null) { }
public AutoResizeTextView(Context context, IAttributeSet attrs) : this(context, attrs, 0) { }
public AutoResizeTextView(Context context, IAttributeSet attrs, int defStyle): base(context, attrs, defStyle)
{
mTextSize = TextSize;
}
protected override void OnTextChanged(ICharSequence text, int start, int lengthBefore, int lengthAfter)
{
base.OnTextChanged(text, start, lengthBefore, lengthAfter);
mNeedsResize = true;
ResetTextSize();
}
protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
{
base.OnSizeChanged(w, h, oldw, oldh);
if (w != oldw || h != oldh)
mNeedsResize = true;
}
public void SetOnResizeListener(OnTextResizeListener listener)
{
mTextResizeListener = listener;
}
public override void SetTextSize([GeneratedEnum] ComplexUnitType unit, float size)
{
base.SetTextSize(unit, size);
mTextSize = TextSize;
}
public override void SetLineSpacing(float add, float mult)
{
base.SetLineSpacing(add, mult);
mSpacingMult = mult;
mSpacingAdd = add;
}
public void SetMaxTextSize(float maxTextSize)
{
mMaxTextSize = maxTextSize;
RequestLayout();
Invalidate();
}
public float GetMaxTextSize()
{
return mMaxTextSize;
}
public void SetMinTextSize(float minTextSize)
{
mMinTextSize = minTextSize;
RequestLayout();
Invalidate();
}
public float GetMinTextSize()
{
return mMinTextSize;
}
public void ResetTextSize()
{
if(mTextSize > 0)
{
base.SetTextSize(ComplexUnitType.Px, mTextSize);
mMaxTextSize = mTextSize;
}
}
protected override void OnLayout(bool changed, int left, int top, int right, int bottom)
{
if(changed || mNeedsResize)
{
int widthLimit = (right - left) - CompoundPaddingLeft - CompoundPaddingRight;
int heightLimit = (bottom - top) - CompoundPaddingBottom - CompoundPaddingTop;
ResizeText(widthLimit, heightLimit);
}
base.OnLayout(changed, left, top, right, bottom);
base.OnLayout(changed, left, top, right, bottom);
}
public void ResizeText()
{
int heightLimit = Height - PaddingBottom - PaddingTop;
int widthLimit = Width - PaddingLeft - PaddingRight;
ResizeText(widthLimit, heightLimit);
}
public void ResizeText(int width, int height)
{
var text = TextFormatted;
if (text == null || text.Length() == 0 || height <= 0 || width <= 0 || mTextSize == 0)
return;
if (TransformationMethod != null)
text = TransformationMethod.GetTransformationFormatted(TextFormatted, this);
TextPaint textPaint = Paint;
float oldTextSize = textPaint.TextSize;
float targetTextSize = mMaxTextSize > 0 ? System.Math.Min(mTextSize, mMaxTextSize) : mTextSize;
int textHeight = GetTextHeight(text, textPaint, width, targetTextSize);
while(textHeight > height && targetTextSize > mMinTextSize)
{
targetTextSize = System.Math.Max(targetTextSize - 2, mMinTextSize);
textHeight = GetTextHeight(text, textPaint, width, targetTextSize);
}
if(AddEllipsis && targetTextSize == mMinTextSize && textHeight > height)
{
TextPaint paint = new TextPaint(textPaint);
StaticLayout layout = new StaticLayout(text, paint, width, Layout.Alignment.AlignNormal, mSpacingMult, mSpacingAdd, false);
if(layout.LineCount > 0)
{
int lastLine = layout.GetLineForVertical(height) - 1;
if (lastLine < 0)
SetText("", BufferType.Normal);
else
{
int start = layout.GetLineStart(lastLine);
int end = layout.GetLineEnd(lastLine);
float lineWidth = layout.GetLineWidth(lastLine);
float ellipseWidth = textPaint.MeasureText(mEllipsis);
while (width < lineWidth + ellipseWidth)
lineWidth = textPaint.MeasureText(text.SubSequence(start, --end + 1).ToString());
SetText(text.SubSequence(0, end) + mEllipsis, BufferType.Normal);
}
}
}
SetTextSize(ComplexUnitType.Px, targetTextSize);
SetLineSpacing(mSpacingAdd, mSpacingMult);
mTextResizeListener?.OnTextResize(this, oldTextSize, targetTextSize);
mNeedsResize = false;
}
private int GetTextHeight(ICharSequence source, TextPaint paint, int width, float textSize)
{
TextPaint paintCopy = new TextPaint(paint);
paintCopy.TextSize = textSize;
StaticLayout layout = new StaticLayout(source, paintCopy, width, Layout.Alignment.AlignNormal, mSpacingMult, mSpacingAdd, false);
return layout.Height;
}
}
}
Related
I'm trying to make a snake game in WPF and I decided to use a grid to display the board.
The snake is supposed to move its x and y position changing the grid column and grid row property. To achieve this I made a SnakePlayer class, a Food class.
In the MainWindow I call the game loop every 200ms and I listen to the keyboard to set the snake direction.
The issue is, even though the snake x, y position changes correctly in the code ( I tested this ),
the snake changes in position are not visualized because it keeps staying in the initial position.
SnakePlayer Class:
namespace Snake
{
internal class SnakePlayer
{
// keeps track of the current direction and makes the snake keep moving
public (int x, int y) Acceleration = (x: 0, y: 1);
//rappresents the coordinate of each snake part
private readonly List<(int x, int y)> Body = new();
public (int x, int y) Head;
public SnakePlayer(int NUMBER_OF_ROWS, int NUMBER_OF_COLUMNS)
{
int x = Convert.ToInt32((NUMBER_OF_ROWS - 1) / 2);
int y = Convert.ToInt32((NUMBER_OF_COLUMNS - 1) / 2);
Body.Add((x, y));
Head = Body.ElementAt(0);
}
public void UpdatePosition()
{
for (int i = Body.Count - 2; i >= 0; i--)
{
(int x, int y) = Body.ElementAt(i);
Body[i + 1] = (x, y);
}
MoveHead();
}
private void MoveHead()
{
// for example if acceleration is (1,0) the head keeps going to the right each time the method is called
Head.x += Acceleration.x;
Head.y += Acceleration.y;
}
public void Show(Grid gameGrid)
{
/*
* i basically erase all the previous snake parts and
* then draw new elements at the new positions
*/
gameGrid.Children.Clear();
Body.ForEach(tail =>
{
Border element = GenerateBodyPart(tail.x, tail.y);
gameGrid.Children.Add(element);
});
}
private static Border GenerateBodyPart(int x, int y)
{
static void AddStyles(Border elem)
{
elem.HorizontalAlignment = HorizontalAlignment.Stretch;
elem.VerticalAlignment = VerticalAlignment.Stretch;
elem.CornerRadius = new CornerRadius(5);
elem.Background = Brushes.Green;
}
Border elem = new();
AddStyles(elem);
Grid.SetColumn(elem, x);
Grid.SetRow(elem, y);
return elem;
}
public void Grow()
{
var prevHead = (Head.x,Head.y);
AddFromBottomOfList(Body,prevHead);
}
public bool Eats((int x, int y) position)
{
return Head.x == position.x && Head.y == position.y;
}
public void SetAcceleration(int x, int y)
{
Acceleration.x = x;
Acceleration.y = y;
UpdatePosition();
}
public bool Dies(Grid gameGrid)
{
bool IsOutOfBounds(List<(int x, int y)> Body)
{
int mapWidth = gameGrid.ColumnDefinitions.Count;
int mapHeight = gameGrid.RowDefinitions.Count;
return Body.Any(tail => tail.x > mapWidth || tail.y > mapHeight || tail.x < 0 || tail.y < 0);
}
bool HitsItsSelf(List<(int x, int y)> Body)
{
return Body.Any((tail) =>
{
bool isHead = Body.IndexOf(tail) == 0;
if (isHead) return false;
return Head.x == tail.x && Head.y == tail.y;
});
}
return IsOutOfBounds(Body) || HitsItsSelf(Body);
}
public bool HasElementAt(int x, int y)
{
return Body.Any(tail => tail.x == x && tail.y == y);
}
private static void AddFromBottomOfList<T>(List<T> List,T Element)
{
List<T> ListCopy = new();
ListCopy.Add(Element);
ListCopy.AddRange(List);
List.Clear();
List.AddRange(ListCopy);
}
}
}
Food Class:
namespace Snake
{
internal class Food
{
public readonly SnakePlayer snake;
public (int x, int y) Position { get; private set; }
public Food(SnakePlayer snake, Grid gameGrid)
{
this.snake = snake;
Position = GetInitialPosition(gameGrid);
Show(gameGrid);
}
private (int x, int y) GetInitialPosition(Grid gameGrid)
{
(int x, int y) getRandomPosition()
{
static int RandomPositionBetween(int min, int max)
{
Random random = new();
return random.Next(min, max);
}
int cols = gameGrid.ColumnDefinitions.Count;
int rows = gameGrid.RowDefinitions.Count;
int x = RandomPositionBetween(0, cols);
int y = RandomPositionBetween(0, rows);
return (x, y);
}
var position = getRandomPosition();
if (snake.HasElementAt(position.x, position.y)) return GetInitialPosition(gameGrid);
return position;
}
public void Show(Grid gameGrid)
{
static void AddStyles(Border elem)
{
elem.HorizontalAlignment = HorizontalAlignment.Stretch;
elem.VerticalAlignment = VerticalAlignment.Stretch;
elem.CornerRadius = new CornerRadius(500);
elem.Background = Brushes.Red;
}
Border elem = new();
AddStyles(elem);
Grid.SetColumn(elem, Position.x);
Grid.SetRow(elem, Position.y);
gameGrid.Children.Add(elem);
}
}
}
MainWindow:
namespace Snake
{
public partial class MainWindow : Window
{
const int NUMBER_OF_ROWS = 15, NUMBER_OF_COLUMNS = 15;
private readonly SnakePlayer snake;
private Food food;
private readonly DispatcherTimer Loop;
public MainWindow()
{
InitializeComponent();
CreateBoard();
snake = new SnakePlayer(NUMBER_OF_ROWS, NUMBER_OF_COLUMNS);
food = new Food(snake, GameGrid);
GameGrid.Focus();
GameGrid.KeyDown += (sender, e) => OnKeySelection(e);
Loop = SetInterval(GameLoop, 200);
}
private void GameLoop()
{
snake.UpdatePosition();
snake.Show(GameGrid);
food.Show(GameGrid);
if (snake.Eats(food.Position))
{
food = new Food(snake, GameGrid);
snake.Grow();
}
else if (snake.Dies(GameGrid))
{
Loop.Stop();
snake.UpdatePosition();
ResetMap();
ShowEndGameMessage("You Died");
}
}
private void OnKeySelection(KeyEventArgs e)
{
if(e.Key == Key.Escape)
{
Close();
return;
}
var DIRECTIONS = new
{
UP = (0, 1),
LEFT = (-1, 0),
DOWN = (0, -1),
RIGHT = (1, 0),
};
Dictionary<string, (int x, int y)> acceptableKeys = new()
{
{ "W", DIRECTIONS.UP },
{ "UP", DIRECTIONS.UP },
{ "A", DIRECTIONS.LEFT },
{ "LEFT", DIRECTIONS.LEFT },
{ "S", DIRECTIONS.DOWN },
{ "DOWN", DIRECTIONS.DOWN },
{ "D", DIRECTIONS.RIGHT },
{ "RIGHT", DIRECTIONS.RIGHT }
};
string key = e.Key.ToString().ToUpper().Trim();
if (!acceptableKeys.ContainsKey(key)) return;
(int x, int y) = acceptableKeys[key];
snake.SetAcceleration(x, y);
}
private void CreateBoard()
{
for (int i = 0; i < NUMBER_OF_ROWS; i++)
GameGrid.RowDefinitions.Add(new RowDefinition());
for (int i = 0; i < NUMBER_OF_COLUMNS; i++)
GameGrid.ColumnDefinitions.Add(new ColumnDefinition());
}
private void ResetMap()
{
GameGrid.Children.Clear();
GameGrid.RowDefinitions.Clear();
GameGrid.ColumnDefinitions.Clear();
}
private void ShowEndGameMessage(string message)
{
TextBlock endGameMessage = new();
endGameMessage.Text = message;
endGameMessage.HorizontalAlignment = HorizontalAlignment.Center;
endGameMessage.VerticalAlignment = VerticalAlignment.Center;
endGameMessage.Foreground = Brushes.White;
GameGrid.Children.Clear();
GameGrid.Children.Add(endGameMessage);
}
private static DispatcherTimer SetInterval(Action cb, int ms)
{
DispatcherTimer dispatcherTimer = new();
dispatcherTimer.Interval = TimeSpan.FromMilliseconds(ms);
dispatcherTimer.Tick += (sender, e) => cb();
dispatcherTimer.Start();
return dispatcherTimer;
}
}
}
MainWindow.xaml:
<Window x:Class="Snake.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Snake"
mc:Ignorable="d"
WindowStyle="None"
Background="Transparent"
WindowStartupLocation="CenterScreen"
Title="MainWindow" Height="600" Width="600" ResizeMode="NoResize" AllowsTransparency="True">
<Border CornerRadius="20" Height="600" Width="600" Background="#FF0D1922">
<Grid x:Name="GameGrid" Focusable="True" ShowGridLines="False"/>
</Border>
</Window>
While I don't fully understand your desired UX for this game, I made a few changes that are producing more meaningful results.
The main reason why your UI isn't updating is because you are never changing your GenerateBodyPart's position. It is always equal to its initial value. Instead of passing the "tail" which never changes, you should be passing the "Head" which has the new position.
Change this:
private static Border GenerateBodyPart(int x, int y)
{
....
Grid.SetColumn(elem, tail.x);
Grid.SetRow(elem, tail.y);
return elem;
}
To be this (notice that I removed the static keyword to get to the Head):
private Border GenerateBodyPart(int x, int y)
{
....
Grid.SetColumn(elem, Head.x);
Grid.SetRow(elem, Head.y);
return elem;
}
Also, your "Directions" are incorrect for UP and DOWN. It should be this:
var DIRECTIONS = new
{
UP = (0, -1),
LEFT = (-1, 0),
DOWN = (0, 1),
RIGHT = (1, 0),
};
After making those changes, the UI was at least updating the snake position. Watch video. I don't know exactly how you want the snake to display, but that's for you to figure out later. :)
Have fun coding!
Here is my full source code for reference: Download here
I want to make the If condition in the isAT to get the position of the line on the screen.Which mean when the mouse on the line and I click on the line I am able to select it.What I need is to able to select the Line when I click on it by the mouse.Thanks for help in advance.
public class MyLine : Shape
{
private float _endY, _endX;
public MyLine() : this(Color.Orange, 0 , 0, 0, 0)
{
}
public MyLine(Color clr, float starX, float starY, float endX, float endY ) : base(clr)
{
X = starX;
Y = starY;
this.endX = endX;
this.endY = endY;
}
public float endX
{
get { return _endX; }
set { _endX = value; }
}
public float endY
{
get { return _endY; }
set { _endY = value; }
}
public override bool IsAT(Point2D pt)
{
if (pt.X > X && pt.Y < Y && pt.X > endX && pt.Y > endY)
return true;
else
return false;
}
}
I can’t realize the possibility of continuing the game after a collision. The snake should stop and start moving after clicking on one of the arrow buttons.
In a collision, a window appears about the loss, I need to continue the game.
I press the button and the following happens:
I don’t understand how I can save the coordinates of the snake just before the collision.
In the moveTimer_Tick method, all elements move, i.e. new coordinates have already appeared at the head and body, then there is a check for collisions with the wall and body. If they are found, a window appears about the loss.
New snake coordinates are not displayed. But after clicking the "Continue" button, an update occurs and the snake climbs to the border.
The question is: how can I save the coordinates of the snake, before the collision, and after continuing to start with them.
namespace Snake{
public partial class MainWindow : Window
{
//The field on which the snake lives
Entity field;
// snake head
Head head;
// whole snake
List<PositionedEntity> snake;
// apple
Apple apple;
//number of points
int score;
// Is movement paused
bool paused;
//time
DispatcherTimer moveTimer;
//constructor form
public MainWindow()
{
InitializeComponent();
snake = new List<PositionedEntity>();
//create field 600x600pixels
field = new Entity(600, 600, "pack://application:,,,/Resources/snake.png");
//create a timer that runs every 300 ms
moveTimer = new DispatcherTimer();
moveTimer.Interval = new TimeSpan(0, 0, 0, 0, 300);
moveTimer.Tick += new EventHandler(moveTimer_Tick);
}
//redraw screen method
private void UpdateField()
{
//update the position of the elements of the snake
foreach (var p in snake)
{
Canvas.SetTop(p.image, p.y);
Canvas.SetLeft(p.image, p.x);
}
//update the position of apple
Canvas.SetTop(apple.image, apple.y);
Canvas.SetLeft(apple.image, apple.x);
//points update
lblScore.Content = String.Format("{0}000", score);
}
//timer tick handler. All movement takes place here.
void moveTimer_Tick(object sender, EventArgs e)
{
// Do not update if movement is paused
if(paused) {
return;
}
//in the reverse order we move all the elements of the snake
foreach (var p in Enumerable.Reverse(snake))
{
p.move();
}
//we check that the head of the snake did not crash into the body
foreach (var p in snake.Where(x => x != head))
{
if (p.x == head.x && p.y == head.y)
{
//we lose
moveTimer.Stop();
GameOver.Visibility = Visibility.Visible;
btnRestart.Visibility = Visibility.Visible;
tbScore.Text = String.Format("SCORE: {0}000", score);
return;
}
}
//check that the head of the snake did not go out of the field
if (head.x < 40 || head.x >= 540 || head.y < 40 || head.y >= 540)
{
//we lose
moveTimer.Stop();
GameOver.Visibility = Visibility.Visible;
btnRestart.Visibility = Visibility.Visible;
tbScore.Text = String.Format("SCORE: {0}000", score);
return;
}
//check that the head of the snake crashed into an apple
if (head.x == apple.x && head.y == apple.y)
{
//increase the score
score++;
//move the apple to a new place
apple.move();
var part = new BodyPart(snake.Last());
canvas1.Children.Add(part.image);
snake.Add(part);
}
UpdateField();
}
private void Window_KeyDown(object sender, KeyEventArgs e)
{
// Unpause movement when any key is pressed
if(paused) {
paused = false;
}
switch (e.Key)
{
case Key.Up:
head.direction = Head.Direction.UP;
break;
case Key.Down:
head.direction = Head.Direction.DOWN;
break;
case Key.Left:
head.direction = Head.Direction.LEFT;
break;
case Key.Right:
head.direction = Head.Direction.RIGHT;
break;
}
}
// "Start"
private void button1_Click(object sender, RoutedEventArgs e)
{
btnStart.Visibility = Visibility.Hidden;
btnRestart.Visibility = Visibility.Hidden;
tBNotEnoughPoints.Visibility = Visibility.Hidden;
score = 0;
snake.Clear();
canvas1.Children.Clear();
// "Game Over"
GameOver.Visibility = Visibility.Hidden;
canvas1.Children.Add(field.image);
apple = new Apple(snake);
canvas1.Children.Add(apple.image);
head = new Head();
snake.Add(head);
canvas1.Children.Add(head.image);
moveTimer.Start();
UpdateField();
}
private void btnContinue_Click(object sender, RoutedEventArgs e)
{
if (score >= 2)
{
GameOver.Visibility = Visibility.Hidden;
btnRestart.Visibility = Visibility.Hidden;
score -= 2;
// Pause movement
paused = true;
moveTimer.Start();
UpdateField();
}
else
{
tBNotEnoughPoints.Visibility = Visibility.Visible;
}
}
public class Entity
{
protected int m_width;
protected int m_height;
Image m_image;
public Entity(int w, int h, string image)
{
m_width = w;
m_height = h;
m_image = new Image();
m_image.Source = (new ImageSourceConverter()).ConvertFromString(image) as ImageSource;
m_image.Width = w;
m_image.Height = h;
}
public Image image
{
get
{
return m_image;
}
}
}
public class PositionedEntity : Entity
{
protected int m_x;
protected int m_y;
public PositionedEntity(int x, int y, int w, int h, string image)
: base(w, h, image)
{
m_x = x;
m_y = y;
}
public virtual void move() { }
public int x
{
get
{
return m_x;
}
set
{
m_x = value;
}
}
public int y
{
get
{
return m_y;
}
set
{
m_y = value;
}
}
}
public class Apple : PositionedEntity
{
List<PositionedEntity> m_snake;
public Apple(List<PositionedEntity> s)
: base(0, 0, 40, 40, "pack://application:,,,/Resources/fruit.png")
{
m_snake = s;
move();
}
public override void move()
{
Random rand = new Random();
do
{
x = rand.Next(13) * 40 + 40 ;
y = rand.Next(13) * 40 + 40 ;
bool overlap = false;
foreach (var p in m_snake)
{
if (p.x == x && p.y == y)
{
overlap = true;
break;
}
}
if (!overlap)
break;
} while (true);
}
}
public class Head : PositionedEntity
{
public enum Direction
{
RIGHT, DOWN, LEFT, UP, NONE
};
Direction m_direction;
public Direction direction {
set
{
m_direction = value;
RotateTransform rotateTransform = new RotateTransform(90 * (int)value);
image.RenderTransform = rotateTransform;
}
}
public Head()
: base(280, 280, 40, 40, "pack://application:,,,/Resources/head.png")
{
image.RenderTransformOrigin = new Point(0.5, 0.5);
m_direction = Direction.NONE;
}
public override void move()
{
switch (m_direction)
{
case Direction.DOWN:
y += 40;
break;
case Direction.UP:
y -= 40;
break;
case Direction.LEFT:
x -= 40;
break;
case Direction.RIGHT:
x += 40;
break;
}
}
}
public class BodyPart : PositionedEntity
{
PositionedEntity m_next;
public BodyPart(PositionedEntity next)
: base(next.x, next.y, 40, 40, "pack://application:,,,/Resources/body.png")
{
m_next = next;
}
public override void move()
{
x = m_next.x;
y = m_next.y;
}
}
}
}
There is something to say about the design of your code, but if you don't care and you want a fast (and ugly) solution you can modify your PositionEntity in order to store old coordinates:
public class PositionedEntity : Entity
{
protected int m_x;
protected int m_y;
protected int m_oldX;
protected int m_oldY;
public PositionedEntity(int x, int y, int w, int h, string image)
: base(w, h, image)
{
m_x = x;
m_y = y;
m_oldX = x;
m_oldY = y;
}
public virtual void move() { }
public virtual void RestorePrevious()
{
m_x = m_oldX;
m_y = m_oldY;
}
public int x
{
get
{
return m_x;
}
set
{
m_oldX = m_x;
m_x = value;
}
}
public int y
{
get
{
return m_y;
}
set
{
m_oldY = m_y;
m_y = value;
}
}
}
When you have a collision you should call the RestorePrevious() on the head and on all the rest of the snake
I am using the DebugConsole script to show the debug output on screen.It works perfectly but appears at the top left corner. I want it to appear inside a panel where I have created a window and a GUI text element and the script gives this option as well. I see the gui text formed as an element in the project console, but is not visible.
I do have a GUI layer
My gui text element is the direct child of a canvas
Camera is set to screen space overlay. I tried worldspace , still not visible.
My code:
namespace OctopartApi
{
using Newtonsoft.Json;
using RestSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
using System.Net;
using UnityEngine.UI;
public class KeywordSearch1 : MonoBehaviour
{
public InputField mainInputField;
public Canvas can;
public Text infoText;
public float x, y;
void Start () {
mainInputField.onEndEdit.AddListener(delegate {LockInput(mainInputField); });
}
void LockInput(InputField input)
{
ExecuteSearch (input.text);
}
public void ExecuteSearch(string inp)
{
// -- your search query --
string query = inp;
string octopartUrlBase = "http://octopart.com/api/v3";
string octopartUrlEndpoint = "parts/search";
string apiKey = "57af648b";
// Create the search request
var client = new RestClient(octopartUrlBase);
var req = new RestRequest(octopartUrlEndpoint, Method.GET)
.AddParameter("apikey", apiKey)
.AddParameter("q", query)
.AddParameter("start", "0")
.AddParameter("limit", "10");
var resp = client.Execute(req);
string octojson = resp.Content;
RootOb rr = JsonUtility.FromJson<RootOb> (octojson);
string hhts = (rr.hits).ToString();
hhts = hhts + rr.user_currency;
infoText.horizontalOverflow = HorizontalWrapMode.Overflow;
infoText.verticalOverflow = VerticalWrapMode.Overflow;
infoText.text = hhts;
// sendR (inp);
// Perform the search and obtain results
/* var resp = client.Execute(req);
var search_response = JsonConvert.DeserializeObject<dynamic>(resp.Content);
Console.WriteLine (search_response);
// Print the number of hits and results
Console.WriteLine("Number of hits: " + search_response["hits"]);
Debug.Log(search_response ["hits"]+"OCTO");
foreach (var result in search_response["results"])
{
var part = result["item"];
Debug.Log(part["brand"]["name"] + "OCTO" + part["mpn"]+part["octopart_url"]);
DebugConsole.Log (part ["brand"] ["name"] + "-- " + part ["mpn"]+" " +part["octopart_url"]);
}*/
}
// -- your API key -- (https://octopart.com/api/register)
private const string APIKEY = "57af648b";
}
}
DebugConsole script :
using UnityEngine;
using System.Collections;
public class DebugConsole : MonoBehaviour
{
public GameObject DebugGui = null; // The GUI that will be duplicated
public Vector3 defaultGuiPosition = new Vector3(0.01F, 0.98F, 0F);
public Vector3 defaultGuiScale = new Vector3(0.5F, 0.5F, 1F);
public Color normal = Color.green;
public Color warning = Color.yellow;
public Color error = Color.red;
public int maxMessages = 30; // The max number of messages displayed
public float lineSpacing = 0.02F; // The amount of space between lines
public ArrayList messages = new ArrayList();
public ArrayList guis = new ArrayList();
public ArrayList colors = new ArrayList();
public bool draggable = true; // Can the output be dragged around at runtime by default?
public bool visible = true; // Does output show on screen by default or do we have to enable it with code?
public bool pixelCorrect = false; // set to be pixel Correct linespacing
public static bool isVisible
{
get
{
return DebugConsole.instance.visible;
}
set
{
DebugConsole.instance.visible = value;
if (value == true)
{
DebugConsole.instance.Display();
}
else if (value == false)
{
DebugConsole.instance.ClearScreen();
}
}
}
public static bool isDraggable
{
get
{
return DebugConsole.instance.draggable;
}
set
{
DebugConsole.instance.draggable = value;
}
}
private static DebugConsole s_Instance = null; // Our instance to allow this script to be called without a direct connection.
public static DebugConsole instance
{
get
{
if (s_Instance == null)
{
s_Instance = FindObjectOfType(typeof(DebugConsole)) as DebugConsole;
if (s_Instance == null)
{
GameObject console = new GameObject();
console.AddComponent<DebugConsole>();
console.name = "DebugConsoleController";
s_Instance = FindObjectOfType(typeof(DebugConsole)) as DebugConsole;
DebugConsole.instance.InitGuis();
}
}
return s_Instance;
}
}
void Awake()
{
s_Instance = this;
InitGuis();
}
protected bool guisCreated = false;
protected float screenHeight =-1;
public void InitGuis()
{
float usedLineSpacing = lineSpacing;
screenHeight = Screen.height;
if(pixelCorrect)
usedLineSpacing = 1.0F / screenHeight * usedLineSpacing;
if (guisCreated == false)
{
if (DebugGui == null) // If an external GUIText is not set, provide the default GUIText
{
DebugGui = new GameObject();
DebugGui.AddComponent<GUIText>();
DebugGui.name = "DebugGUI(0)";
DebugGui.transform.position = defaultGuiPosition;
DebugGui.transform.localScale = defaultGuiScale;
}
// Create our GUI objects to our maxMessages count
Vector3 position = DebugGui.transform.position;
guis.Add(DebugGui);
int x = 1;
while (x < maxMessages)
{
position.y -= usedLineSpacing;
GameObject clone = null;
clone = (GameObject)Instantiate(DebugGui, position, transform.rotation);
clone.name = string.Format("DebugGUI({0})", x);
guis.Add(clone);
position = clone.transform.position;
x += 1;
}
x = 0;
while (x < guis.Count)
{
GameObject temp = (GameObject)guis[x];
temp.transform.parent = DebugGui.transform;
x++;
}
guisCreated = true;
} else {
// we're called on a screensize change, so fiddle with sizes
Vector3 position = DebugGui.transform.position;
for(int x=0;x < guis.Count; x++)
{
position.y -= usedLineSpacing;
GameObject temp = (GameObject)guis[x];
temp.transform.position= position;
}
}
}
bool connectedToMouse = false;
void Update()
{
// If we are visible and the screenHeight has changed, reset linespacing
if (visible == true && screenHeight != Screen.height)
{
InitGuis();
}
if (draggable == true)
{
if (Input.GetMouseButtonDown(0))
{
if (connectedToMouse == false && DebugGui.GetComponent<GUIText>().HitTest((Vector3)Input.mousePosition) == true)
{
connectedToMouse = true;
}
else if (connectedToMouse == true)
{
connectedToMouse = false;
}
}
if (connectedToMouse == true)
{
float posX = DebugGui.transform.position.x;
float posY = DebugGui.transform.position.y;
posX = Input.mousePosition.x / Screen.width;
posY = Input.mousePosition.y / Screen.height;
DebugGui.transform.position = new Vector3(posX, posY, 0F);
}
}
}
//+++++++++ INTERFACE FUNCTIONS ++++++++++++++++++++++++++++++++
public static void Log(string message, string color)
{
DebugConsole.instance.AddMessage(message, color);
}
//++++ OVERLOAD ++++
public static void Log(string message)
{
DebugConsole.instance.AddMessage(message);
}
public static void Clear()
{
DebugConsole.instance.ClearMessages();
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//---------- void AddMesage(string message, string color) ------
//Adds a mesage to the list
//--------------------------------------------------------------
public void AddMessage(string message, string color)
{
messages.Add(message);
colors.Add(color);
Display();
}
//++++++++++ OVERLOAD for AddMessage ++++++++++++++++++++++++++++
// Overloads AddMessage to only require one argument(message)
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public void AddMessage(string message)
{
messages.Add(message);
colors.Add("normal");
Display();
}
//----------- void ClearMessages() ------------------------------
// Clears the messages from the screen and the lists
//---------------------------------------------------------------
public void ClearMessages()
{
messages.Clear();
colors.Clear();
ClearScreen();
}
//-------- void ClearScreen() ----------------------------------
// Clears all output from all GUI objects
//--------------------------------------------------------------
void ClearScreen()
{
if (guis.Count < maxMessages)
{
//do nothing as we haven't created our guis yet
}
else
{
int x = 0;
while (x < guis.Count)
{
GameObject gui = (GameObject)guis[x];
gui.GetComponent<GUIText>().text = "";
//increment and loop
x += 1;
}
}
}
//---------- void Prune() ---------------------------------------
// Prunes the array to fit within the maxMessages limit
//---------------------------------------------------------------
void Prune()
{
int diff;
if (messages.Count > maxMessages)
{
if (messages.Count <= 0)
{
diff = 0;
}
else
{
diff = messages.Count - maxMessages;
}
messages.RemoveRange(0, (int)diff);
colors.RemoveRange(0, (int)diff);
}
}
//---------- void Display() -------------------------------------
// Displays the list and handles coloring
//---------------------------------------------------------------
void Display()
{
//check if we are set to display
if (visible == false)
{
ClearScreen();
}
else if (visible == true)
{
if (messages.Count > maxMessages)
{
Prune();
}
// Carry on with display
int x = 0;
if (guis.Count < maxMessages)
{
//do nothing as we havent created our guis yet
}
else
{
while (x < messages.Count)
{
GameObject gui = (GameObject)guis[x];
//set our color
switch ((string)colors[x])
{
case "normal": gui.GetComponent<GUIText>().material.color = normal;
break;
case "warning": gui.GetComponent<GUIText>().material.color = warning;
break;
case "error": gui.GetComponent<GUIText>().material.color = error;
break;
}
//now set the text for this element
gui.GetComponent<GUIText>().text = (string)messages[x];
//increment and loop
x += 1;
}
}
}
}
}// End DebugConsole Class
In Unity UI, LayoutElement has a min, prefered and flxible size, but it do not have a max size property.
For example if I have a text1 and
layoutElement.flxibleWith = 1
layoutElement.minHeight = 19
text1 with one line txt:
But when I load text in text1 it continues spreading it height with no limits:
I have made a script:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
[ExecuteInEditMode]
[RequireComponent(typeof(LayoutElement))]
public class LayoutElementMaxSize : MonoBehaviour
{
private LayoutElement layoutElement;
private ContentSizeFitter contentSizeFitter;
private RectTransform rectransform;
public bool controllWidth;
public bool controllHeight;
public float maxHight;
public float maxWidth;
void Start()
{
layoutElement = GetComponent<LayoutElement>();
rectransform = GetComponent<RectTransform>();
}
public void Update()
{
if(rectransform.hasChanged)
{
rectransform.hasChanged = false;
if (controllHeight)
{
layoutElement.preferredHeight = -1;
layoutElement.CalculateLayoutInputHorizontal();
layoutElement.CalculateLayoutInputVertical();
if (rectransform.rect.height >= maxHight)
{
layoutElement.preferredHeight = maxHight;
}
}
if (controllWidth)
{
if (rectransform.rect.height >= maxWidth)
{
layoutElement.preferredWidth = maxWidth;
}
else
{
layoutElement.preferredWidth = -1;
}
}
}
}}
but it is not full filing my requirement plz take a look on it ..
I know this is an old question, but I was looking for something like this and I end up rewriting your class and it now works fine for me. Instead of just making another MonoBehaviour I override the LayoutElement, I also added an custom inspector to make it easy to edit it. Hope my solution could help you or anyone else that would like something like this.
using UnityEngine;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
[RequireComponent(typeof(RectTransform))]
[System.Serializable]
public class LayoutMaxSize : LayoutElement
{
public float maxHeight = -1;
public float maxWidth = -1;
public override void CalculateLayoutInputHorizontal()
{
base.CalculateLayoutInputHorizontal();
UpdateMaxSizes();
}
public override void CalculateLayoutInputVertical()
{
base.CalculateLayoutInputVertical();
UpdateMaxSizes();
}
protected override void OnRectTransformDimensionsChange()
{
base.OnRectTransformDimensionsChange();
UpdateMaxSizes();
}
protected override void OnValidate()
{
base.OnValidate();
UpdateMaxSizes();
}
private void UpdateMaxSizes()
{
if (maxHeight != -1)
{
if (preferredHeight == -1 && maxHeight < GetComponent<RectTransform>().sizeDelta.y)
{
preferredHeight = maxHeight;
}
else if (preferredHeight != -1 && transform.childCount > 0)
{
bool first = true;
float biggestY = 0;
float lowestY = 0;
for (int i = 0; i < transform.childCount; i++)
{
var childrenTransform = transform.GetChild(i).GetComponent<RectTransform>();
if (childrenTransform == null) continue;
var childPos = childrenTransform.localPosition;
var childSize = childrenTransform.sizeDelta;
var childPivot = childrenTransform.pivot;
if(first)
{
biggestY = childPos.y + (childSize.y * (1f - childPivot.y));
lowestY = childPos.y - (childSize.y * childPivot.y);
}
else
{
biggestY = Mathf.Max(biggestY, childPos.y + (childSize.y * (1f - childPivot.y)));
lowestY = Mathf.Min(lowestY, childPos.y - (childSize.y * childPivot.y));
}
first = false;
}
if (first) return;
var childrenYSize = Mathf.Abs(biggestY - lowestY);
if(preferredHeight > childrenYSize)
{
preferredHeight = -1;
}
}
}
if (maxWidth != -1)
{
if (preferredWidth == -1 && maxWidth < GetComponent<RectTransform>().sizeDelta.x)
{
preferredWidth = maxWidth;
}
else if (preferredWidth != -1 && transform.childCount > 0)
{
bool first = true;
float biggestX = 0;
float lowestX = 0;
for (int i = 0; i < transform.childCount; i++)
{
var childrenTransform = transform.GetChild(i).GetComponent<RectTransform>();
if (childrenTransform == null) continue;
var childPos = childrenTransform.localPosition;
var childSize = childrenTransform.sizeDelta;
var childPivot = childrenTransform.pivot;
if (first)
{
biggestX = childPos.x + (childSize.x * (1f - childPivot.x));
lowestX = childPos.x - (childSize.x * childPivot.x);
}
else
{
biggestX = Mathf.Max(biggestX, childPos.x + (childSize.x * (1f - childPivot.x)));
lowestX = Mathf.Min(lowestX, childPos.x - (childSize.x * childPivot.x));
}
first = false;
}
if (first) return;
var childrenXSize = Mathf.Abs(biggestX - lowestX);
if (preferredWidth > childrenXSize)
{
preferredWidth = -1;
}
}
}
}
}
#if UNITY_EDITOR
[CustomEditor(typeof(LayoutMaxSize))]
public class LayoutMaxSizeEditor : Editor
{
public override void OnInspectorGUI()
{
LayoutMaxSize layoutMax = target as LayoutMaxSize;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel("Ignore Layout");
layoutMax.ignoreLayout = EditorGUILayout.Toggle(layoutMax.ignoreLayout);
EditorGUILayout.EndHorizontal();
if (!layoutMax.ignoreLayout)
{
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel("Min Width");
var allowMinWidth = EditorGUILayout.Toggle(layoutMax.minWidth != -1);
if (allowMinWidth)
{
if (layoutMax.minWidth == -1) layoutMax.minWidth = 0;
layoutMax.minWidth = EditorGUILayout.FloatField(layoutMax.minWidth);
}
else if (layoutMax.minWidth != -1)
{
layoutMax.minWidth = -1;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel("Min Height");
var allowMinHeight = EditorGUILayout.Toggle(layoutMax.minHeight != -1);
if (allowMinHeight)
{
if (layoutMax.minHeight == -1) layoutMax.minHeight = 0;
layoutMax.minHeight = EditorGUILayout.FloatField(layoutMax.minHeight);
}
else if (layoutMax.minHeight != -1)
{
layoutMax.minHeight = -1;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel("Max Width");
var allowMaxWidth = EditorGUILayout.Toggle(layoutMax.maxWidth != -1);
if (allowMaxWidth)
{
if (layoutMax.maxWidth == -1) layoutMax.maxWidth = Mathf.Max(0, layoutMax.minWidth);
layoutMax.maxWidth = Mathf.Max(EditorGUILayout.FloatField(layoutMax.maxWidth), layoutMax.minWidth);
}
else if(layoutMax.maxWidth != -1)
{
layoutMax.maxWidth = -1;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel("Max Height");
var allowMaxHeight = EditorGUILayout.Toggle(layoutMax.maxHeight != -1);
if (allowMaxHeight)
{
if (layoutMax.maxHeight == -1) layoutMax.maxHeight = Mathf.Max(0, layoutMax.minHeight);
layoutMax.maxHeight = Mathf.Max(EditorGUILayout.FloatField(layoutMax.maxHeight), layoutMax.minHeight);
}
else if (layoutMax.maxHeight != -1)
{
layoutMax.maxHeight = -1;
}
EditorGUILayout.EndHorizontal();
}
}
}
#endif
I wrote a new script which includes maxheight and maxwidth field for layout element it is not fuly tested but if you want you can use it.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.UI;
#endif
[RequireComponent(typeof(RectTransform))]
[System.Serializable]
public class LayoutElementWithMaxValues : LayoutElement {
public float maxHeight;
public float maxWidth;
public bool useMaxWidth;
public bool useMaxHeight;
bool ignoreOnGettingPreferedSize;
public override int layoutPriority {
get => ignoreOnGettingPreferedSize ? -1 : base.layoutPriority;
set => base.layoutPriority = value; }
public override float preferredHeight {
get {
if (useMaxHeight) {
var defaultIgnoreValue = ignoreOnGettingPreferedSize;
ignoreOnGettingPreferedSize = true;
var baseValue = LayoutUtility.GetPreferredHeight(transform as RectTransform);
ignoreOnGettingPreferedSize = defaultIgnoreValue;
return baseValue > maxHeight ? maxHeight : baseValue;
}
else
return base.preferredHeight;
}
set => base.preferredHeight = value;
}
public override float preferredWidth {
get {
if (useMaxWidth) {
var defaultIgnoreValue = ignoreOnGettingPreferedSize;
ignoreOnGettingPreferedSize = true;
var baseValue = LayoutUtility.GetPreferredWidth(transform as RectTransform);
ignoreOnGettingPreferedSize = defaultIgnoreValue;
return baseValue > maxWidth ? maxWidth : baseValue;
}
else
return base.preferredWidth;
}
set => base.preferredWidth = value;
}
}
#if UNITY_EDITOR
[CustomEditor(typeof(LayoutElementWithMaxValues), true)]
[CanEditMultipleObjects]
public class LayoutMaxSizeEditor : LayoutElementEditor {
LayoutElementWithMaxValues layoutMax;
SerializedProperty maxHeightProperty;
SerializedProperty maxWidthProperty;
SerializedProperty useMaxHeightProperty;
SerializedProperty useMaxWidthProperty;
RectTransform myRectTransform;
protected override void OnEnable() {
base.OnEnable();
layoutMax = target as LayoutElementWithMaxValues;
myRectTransform = layoutMax.transform as RectTransform;
maxHeightProperty = serializedObject.FindProperty(nameof(layoutMax.maxHeight));
maxWidthProperty = serializedObject.FindProperty(nameof(layoutMax.maxWidth));
useMaxHeightProperty = serializedObject.FindProperty(nameof(layoutMax.useMaxHeight));
useMaxWidthProperty = serializedObject.FindProperty(nameof(layoutMax.useMaxWidth));
}
public override void OnInspectorGUI() {
Draw(maxWidthProperty, useMaxWidthProperty);
Draw(maxHeightProperty, useMaxHeightProperty);
serializedObject.ApplyModifiedProperties();
EditorGUILayout.Space();
base.OnInspectorGUI();
}
void Draw(SerializedProperty property, SerializedProperty useProperty) {
Rect position = EditorGUILayout.GetControlRect();
GUIContent label = EditorGUI.BeginProperty(position, null, property);
Rect fieldPosition = EditorGUI.PrefixLabel(position, label);
Rect toggleRect = fieldPosition;
toggleRect.width = 16;
Rect floatFieldRect = fieldPosition;
floatFieldRect.xMin += 16;
var use = EditorGUI.Toggle(toggleRect, useProperty.boolValue);
useProperty.boolValue = use;
if (use) {
EditorGUIUtility.labelWidth = 4;
property.floatValue = EditorGUI.FloatField(floatFieldRect, new GUIContent(" "), property.floatValue);
EditorGUIUtility.labelWidth = 0;
}
EditorGUI.EndProperty();
}
}
#endif