XamarinForms sticky header - xamarin

Im searching for a solution represented here as a gif from my designer: enter link description here
Basically, I need a list, with a header, or with a another view (grid, or stacklayout). On a scroll, I need to catch event (scrolling down, scrolling up) and to move list with that header.
Can you suggest me some referrals?
Here is the example code from syncfusion:
https://www.syncfusion.com/downloads/support/directtrac/general/ze/AnimateHeaderOnScroll1119606059

You can achieve your requirement by handling Scrolled event as below,
public MainPage()
{
InitializeComponent();
container = _listView.GetVisualContainer();
_scrollView = _listView.GetScrollView();
_scrollView.Scrolled += ScrollView_Scrolled;
}
private void ScrollView_Scrolled(object sender, ScrolledEventArgs e)
{
scrollOffet = (double)container.GetType().GetRuntimeProperties().First(p => p.Name == "ScrollOffset").GetValue(container);
if (e.ScrollY == 0)
(BindingContext as MainViewModel).CanPassTouch = true;
}
private void PanGestureRecognizer_PanUpdated(object sender, PanUpdatedEventArgs e)
{
if(e.StatusType == GestureStatus.Running)
{
var y = e.TotalY;
//Up scroll
if (y < 0)
{
if (!_originalHeaderHeight.HasValue)
{
_originalHeaderHeight = _headerView.Height;
}
var newHeight = _originalHeaderHeight.Value + y;
_headerView.HeightRequest = newHeight > MIN_HEADER_HEIGHT ? newHeight : MIN_HEADER_HEIGHT;
}
//Down scroll
else
{
if (!_originalHeaderHeight.HasValue)
{
_originalHeaderHeight = _headerView.Height;
}
var newHeight = _originalHeaderHeight.Value + y;
_headerView.HeightRequest = newHeight < MAX_HEADER_HEIGHT ? newHeight : MAX_HEADER_HEIGHT;
}
//Enable InputTransparent for SfListView, to enable the ListView scrolling
//after reaching the Header min/max heights based on scrolling.
if (_headerView.HeightRequest == MIN_HEADER_HEIGHT && y < 0)
(BindingContext as MainViewModel).CanPassTouch = false;
if (_headerView.HeightRequest == MAX_HEADER_HEIGHT && scrollOffet > 0)
(BindingContext as MainViewModel).CanPassTouch = false;
}
}
Sample

Related

Xamarin.Android Camera Touch to Focus

I am using Xamarin.Android to use inbuilt camera app to take a photo
but there are two missed things that I cant do and I have been googling them for long time:
I want to get a msg or popup (anything) after pressing the button to take a photo like "photo taken"
I want to let the user focus on any point of the camera - TAP TO FOCUS
async void TakePhotoButtonTapped(object sender, EventArgs e)
{
camera.StopPreview();
Android.Hardware.Camera.Parameters parameters = camera.GetParameters();
parameters.FocusMode = global::Android.Hardware.Camera.Parameters.FocusModeAuto;
camera.SetParameters(parameters);
var image = textureView.Bitmap;
try
{
var absolutePath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDcim).AbsolutePath;
var folderPath = absolutePath + "/Camera";
var filePath = System.IO.Path.Combine(folderPath, string.Format("photo_{0}.jpg", Guid.NewGuid()));
var fileStream = new FileStream(filePath, FileMode.Create);
await image.CompressAsync(Bitmap.CompressFormat.Jpeg, 92, fileStream);
fileStream.Close();
image.Recycle();
var intent = new Android.Content.Intent(Android.Content.Intent.ActionMediaScannerScanFile);
var file = new Java.IO.File(filePath);
var uri = Android.Net.Uri.FromFile(file);
intent.SetData(uri);
MainActivity.Instance.SendBroadcast(intent);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(#" ", ex.Message);
}
camera.StartPreview();
}
I tried this but not working:
public void OnAutoFocus(bool success, Android.Hardware.Camera camera)
{
var parameters = camera.GetParameters();
if (parameters.FocusMode != Android.Hardware.Camera.Parameters.FocusModeContinuousPicture)
{
parameters.FocusMode = Android.Hardware.Camera.Parameters.FocusModeContinuousPicture;
if (parameters.MaxNumFocusAreas > 0)
{
parameters.FocusAreas = null;
}
camera.SetParameters(parameters);
camera.StartPreview();
}
}
public bool OnTouch(Android.Views.View view, MotionEvent e)
{
if (camera != null)
{
var parameters = camera.GetParameters();
camera.CancelAutoFocus();
Rect focusRect = CalculateTapArea(e.GetX(), e.GetY(), 1f);
if (parameters.FocusMode != Android.Hardware.Camera.Parameters.FocusModeAuto)
{
parameters.FocusMode = Android.Hardware.Camera.Parameters.FocusModeAuto;
}
if (parameters.MaxNumFocusAreas > 0)
{
List<Area> mylist = new List<Area>();
mylist.Add(new Android.Hardware.Camera.Area(focusRect, 1000));
parameters.FocusAreas = mylist;
}
try
{
camera.CancelAutoFocus();
camera.SetParameters(parameters);
camera.StartPreview();
camera.AutoFocus(this);
}
catch (System.Exception ex)
{
Console.WriteLine(ex.ToString());
Console.Write(ex.StackTrace);
}
return true;
}
return false;
}
private Rect CalculateTapArea(object x, object y, float coefficient)
{
var focusAreaSize = 500;
int areaSize = Java.Lang.Float.ValueOf(focusAreaSize * coefficient).IntValue();
int left = clamp((int) x - areaSize / 2, 0, textureView.Width - areaSize);
int top = clamp((int) y - areaSize / 2, 0, textureView.Height - areaSize);
RectF rectF = new RectF(left, top, left + areaSize, top + areaSize);
Matrix.MapRect(rectF);
return new Rect((int) System.Math.Round(rectF.Left), (int) System.Math.Round(rectF.Top), (int) System.Math.Round(rectF.Right),
(int) System.Math.Round(rectF.Bottom));
}
private int clamp(int x, int min, int max)
{
if (x > max)
{
return max;
}
if (x < min)
{
return min;
}
return x;
}
For focusing the camera when touching the preview you will need to:
Add a touch event handler to listen for the user touching the preview
Get the X and Y coordinates from that touch event, which are usually in the event arguments
Create a rectangle to focus to tell the Android Camera where to focus and in which area
Set FocusAreas and MeteringAreas on Camera.Parameters from your rectangle
Set the new Camera.Parameters on the camera
Set a AutoFocus callback on the camera
When the callback triggers, remove the callback from the camera, and cancel auto focus
To notify the user about a picture being taken, you can use a Toast or create a area in your preview where you want to show such messages. It is entirely up to you how you want to notify the user.

Round Shape Icon or Button On Bottom Tabbed Bar Xamarin Forms

I am trying to get the above look on my tabbed bar in xamarin forms, i tried customizing the tabbed bar using renderer and still was not able to get the expected output
output i am getting
till now this is what i have tried
[assembly: ExportRenderer(typeof(BottomNavTabPage), typeof(BottomNavTabPageRenderer))]
namespace HealthMobile.Droid.Renderers
{
public class BottomNavTabPageRenderer : TabbedPageRenderer
{
private bool _isShiftModeSet;
public BottomNavTabPageRenderer(Context context)
: base(context)
{
}
protected override void OnVisibilityChanged(Android.Views.View changedView, [GeneratedEnum] ViewStates visibility)
{
base.OnVisibilityChanged(changedView, visibility);
var tabs = changedView.FindViewById<TabLayout>(Resource.Id.sliding_tabs);
if (tabs != null)
{
ViewGroup vg = (ViewGroup)tabs.GetChildAt(0);
int tabsCount = vg.ChildCount;
}
}
//protected override void DispatchDraw (global::Android.Graphics.Canvas canvas)
// {
// base.DispatchDraw (canvas);
// SetTabIcons();
// // var tabLayout = (TabLayout)GetChildAt(1);
// }
// private void SetTabIcons()
// {
// var element = this.Element;
// if (null == element)
// {
// return;
// }
// Activity activity = this.Context as Activity;
// if ((null != activity) && (null != activity.ActionBar) && (activity.ActionBar.TabCount > 0))
// {
// for (int i = 0; i < element.Children.Count; i += 1)
// {
// var tab = activity.ActionBar.GetTabAt(i);
// var page = element.Children[i];
// if ((null != tab) && (null != page) && (null != page.Icon)
// && (tab.CustomView == null))
// {
// var resourceId = activity.Resources.GetIdentifier(page.Icon.File.ToLowerInvariant(), "drawable", this.Context.PackageName);
// LinearLayout tabHeader
// = new LinearLayout(activity) { Orientation = Orientation.Vertical };
// ImageView tabImg = new ImageView(activity);
// TextView tabTitle = new TextView(activity);
// tabImg.SetImageResource(resourceId);
// tabTitle.Text = page.Title;
// tabTitle.SetTextColor(Android.Graphics.Color.White);
// tabHeader.AddView(tabTitle);
// tabHeader.AddView(tabImg);
// tab.SetCustomView(tabHeader);
// }
// }
// }
// }
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
{
base.OnElementChanged(e);
var childViews = GetAllChildViews(ViewGroup);
//tab.SetIcon(Resource.Drawable.icon);
var scale = Resources.DisplayMetrics.Density;
var paddingDp = 0;
var dpAsPixels = (int)(paddingDp * scale + 0.5f);
foreach (var childView in childViews)
{
if (childView is BottomNavigationItemView tab)
{
//tab.SetPadding(-50, -100, -50, -100);
}
else if (childView is TextView textView)
{
textView.SetTextColor(Android.Graphics.Color.Transparent);
}
}
}
protected override void SetTabIcon(TabLayout.Tab tab, FileImageSource icon)
{
base.SetTabIcon(tab, icon);
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
try
{
if (!_isShiftModeSet)
{
var children = GetAllChildViews(ViewGroup);
if (children.SingleOrDefault(x => x is BottomNavigationView) is BottomNavigationView bottomNav)
{
bottomNav.SetShiftMode(false, false);
_isShiftModeSet = true;
}
}
}
catch (Exception e)
{
Console.WriteLine($"Error setting ShiftMode: {e}");
}
}
private List<View> GetAllChildViews(View view)
{
if (!(view is ViewGroup group))
{
return new List<View> {view };
}
var result = new List<View>();
for (int i = 0; i < group.ChildCount; i++)
{
var child = group.GetChildAt(i);
var childList = new List<View> {child};
childList.AddRange(GetAllChildViews(child));
result.AddRange(childList);
}
return result.Distinct().ToList();
}
}
}
i am trying to make this look like this somewhat
output expecting
also i tried setting up the icons but SetTabIcons method never get triggered

Xamarin Forms Custom Renderer iOS UICollectionView scrolling in both directions / horizontal – vertical scrolling

Xamarin Forms Custom Renderer iOS UICollectionView scrolling in both directions / horizontal – vertical scrolling
Intention: Implementation of an interactive Grid which scroll horizontally and vertically .
Problem:
The grid scrolls in both direction that much laggy. After scrolling with the finger you have to wait some seconds to see an reaction of the app.
We have implemented an UICollectionView in the same way in an native swift project, and it scrolls fluently. So I think the problem is rather the way of implementation than the rendering process.
With instruments I could find out that the CoreFoundation(RunLoops) cost the most of time(11s). So I guess its a threading problem.
Why I need to customize the UICollectionViewLayout to achieve horizontal scrolling? Because I need the ability to modify the width of single cells and other customizations too.
So the only way for scrolling in both direction I see, is to customize the UICollectionViewLayout.
Implementation:
Xamarin.Forms Project:
Create Custom Control (MyGrid) in Xamarin Forms, which extends from View Class:
public class MyGrid : View
{
public MyGrid() : base()
{
}
}
Use Custom Control ( MyGrid) in Xamarin Forms ContentPage):
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:GridDemo"
x:Class="GridDemo.GridDemoPage">
<ContentPage.Content>
<local:MyGrid
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
BackgroundColor="White"/>
</ContentPage.Content>
</ContentPage>
Xamarin.iOS Project:
Implement Custom Renderer for MyGrid Class in iOS project:
[assembly: ExportRenderer(typeof(MyGrid), typeof(MyGridRenderer))]
namespace GridDemo.iOS
{
public class MyGridRenderer : ViewRenderer<MyGrid, IOSGrid>
{
public MyGridRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<MyGrid> e)
{
base.OnElementChanged(e);
if (Control == null)
{
MyGrid myGrid = (MyGrid)e.NewElement;
List<List<string>> values = myGrid.Source;
var list = new List<CustomIOSGridCell>();
var column = 0;
var row = 0;
var maxColumnLength = new int[myGrid.ColumnCount];
for (int i = 0; i < myGrid.RowCount; i++)
{
for (int j = 0; j < myGrid.ColumnCount; j++)
{
var array = values[i];
var stringLength = array.Aggregate("", (max, cur) => max.Length > cur.Length ? max : cur);
if (stringLength.Length > maxColumnLength[j])
{
maxColumnLength[j] = stringLength.Length;
}
list.Add(new CustomIOSGridCell(values[i][j));
}
}
var grid = new IOSGrid(this.Bounds, new IOSGridLayout(myGrid.ColumnCount, myGrid.RowCount, maxColumnLength));
grid.AddValues(list, myGrid.ColumnCount, myGrid.RowCount);
SetNativeControl(grid);
}
if (e.OldElement != null)
{
// Unsubscribe from event handlers and cleanup any resources
}
if (e.NewElement != null)
{
// Configure the control and subscribe to event handlers
}
}
}
}
Implement native control(iOSGrid), the corresponding Control to Custom Xamarin Forms Control (MyGrid):
public class IOSGrid : UICollectionView
{
List<CustomIOSGridCell> values = new List<CustomIOSGridCell>();
public IOSGrid(CGRect frame, IOSGridLayout collectionViewLayout) : base(frame, collectionViewLayout)
{
this.RegisterClassForCell(typeof(CustomCollectionViewCell), CustomCollectionViewCell.CellID);
BackgroundColor = UIColor.Blue;
}
public void AddValues(List<CustomIOSGridCell> values, int columncount, int rowCount)
{
this.values.AddRange(values);
this.Source = new CustomCollectionSource(this.values, rowCount, columncount);
this.ReloadData();
}
}
Implement Custom UICollectionViewLayout for IOSGrid(UICollectionView) to provide horizontal AND vertical scrolling
public class IOSGridLayout : UICollectionViewLayout
{
private Timer timer;
enum Direction { up, down ,leftRight, none }
int columnsCount = 0;
int rowCount = 0;
CoreGraphics.CGSize[] itemsSize = null;
CoreGraphics.CGSize contentSize = CoreGraphics.CGSize.Empty;
int[] maxLength;
public CGRect currentRect = CGRect.Empty;
CGPoint currentCorner = new CGPoint(-1, -1);
UICollectionViewLayoutAttributes[,] itemAttributes;
public IOSGridLayout(int columnsCount, int rowCount, int[] maxLength)
{
this.columnsCount = columnsCount;
this.rowCount = rowCount;
this.maxLength = maxLength;
itemAttributes = new UICollectionViewLayoutAttributes[rowCount, columnsCount];
}
public override void PrepareLayout()
{
if (CollectionView == null) return;
var collectionView = CollectionView;
if (collectionView.NumberOfSections() == 0) return;
if (itemAttributes.Length != collectionView.NumberOfSections())
{
generateItemAttributes(collectionView);
return;
}
for (int section = 0; section < collectionView.NumberOfSections(); section++)
{
for (int item = 0; item < collectionView.NumberOfItemsInSection(section); item++)
{
if (section != 0 && item != 0)
{
continue;
}
var attributes = LayoutAttributesForItem(NSIndexPath.FromItemSection(item, section)); }
}
}
public override CGSize CollectionViewContentSize
{
get { return contentSize; }
}
public override UICollectionViewLayoutAttributes LayoutAttributesForItem(NSIndexPath indexPath)
{
return itemAttributes[indexPath.Section, indexPath.Row];
}
public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect(CGRect rect)
{
var attributes = new List<UICollectionViewLayoutAttributes>();
// calculate actual shown attributes
return attributes.ToArray();
}
public override bool ShouldInvalidateLayoutForBoundsChange(CGRect newBounds)
{
return true;
}
private void generateItemAttributes(UICollectionView collectionView)
{
if (itemsSize?.Length != columnsCount)
{
CalculateItemSizes();
}
var column = 0;
nfloat xOffset = 0;
nfloat yOffset = 0;
nfloat contentWidth = 0;
itemAttributes = new UICollectionViewLayoutAttributes[rowCount, columnsCount];
var se = collectionView.NumberOfSections();
for (int section = 0; section < rowCount; section++)
{
var sectionAttributes = new UICollectionViewLayoutAttributes[columnsCount];
for (int index = 0; index < columnsCount; index++)
{
var itemSize = itemsSize[index];
var indexPath = NSIndexPath.FromItemSection(index, section);
var attributes = UIKit.UICollectionViewLayoutAttributes.CreateForCell(indexPath);
attributes.Frame = new CGRect(xOffset, yOffset, itemSize.Width, itemSize.Height).Integral();
if (section == 0)
{
var frame = attributes.Frame;
frame.Y = collectionView.ContentOffset.Y;
attributes.Frame = frame;
}
if (index == 0)
{
var frame = attributes.Frame;
frame.X = collectionView.ContentOffset.X;
attributes.Frame = frame;
}
sectionAttributes[index]=attributes;
xOffset += itemSize.Width;
column += 1;
if (column == columnsCount)
{
if (xOffset > contentWidth)
{
contentWidth = xOffset;
}
column = 0;
xOffset = 0;
yOffset += itemSize.Height;
}
}
for (int i = 0; i < sectionAttributes.Length; i++)
{
itemAttributes[section, i] = sectionAttributes[i];
}
}
var attr = itemAttributes[rowCount-1,columnsCount-1];
if (attr != null)
{
contentSize = new CGSize(contentWidth, attr.Frame.GetMaxY());
}
}
private void CalculateItemSizes()
{
itemsSize = new CGSize[columnsCount];
for (int index = 0; index < columnsCount; index++)
{
itemsSize[index] = SizeForItemWithColumnIndex(index);
}
}
private CGSize SizeForItemWithColumnIndex(int index)
{
// CollectionView.CellForItem()
string text = "";
for (int i = 0; i < maxLength[index]; i++)
{
text += "M";
}
NSString ma = new NSString(text);
var size = ma.StringSize(UIFont.SystemFontOfSize(14));
size.Height = 35;
return size;
}
}
Implement Custom UICollectionViewSource for IOSGrid(UICollectionView):
public class CustomCollectionSource : UICollectionViewSource
{
private readonly List<CustomIOSGridCell> values = new List<CustomIOSGridCell>();
private readonly int rowCount = 0;
private readonly int columnCount = 0;
public CustomCollectionSource(List<CustomIOSGridCell> values, int rowCount, int columnCount)
{
this.values = values;
this.rowCount = rowCount;
this.columnCount = columnCount;
}
public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
return rowCount;
}
public override nint NumberOfSections(UICollectionView collectionView)
{
return columnCount;
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var cell = (CustomCollectionViewCell)collectionView.DequeueReusableCell(CustomCollectionViewCell.CellID, indexPath);
cell.UpdateCell(values[indexPath.Row].Text);
return cell;
}
}
Implement Custom UICollectionViewCell for IOSGrid(UICollectionView):
public class CustomCollectionViewCell : UICollectionViewCell
{
public UILabel mainLabel;
public static NSString CellID = new NSString("customCollectionCell");
[Export("initWithFrame:")]
public CustomCollectionViewCell(CGRect frame) : base(frame)
{
// Default
ContentView.Layer.BorderColor = UIColor.Blue.CGColor;
ContentView.Layer.BorderWidth = 1.0f;
ContentView.Layer.BackgroundColor = UIColor.White.CGColor;
mainLabel = new UILabel();
ContentView.AddSubview( mainLabel );
}
public void UpdateCell(string text)
{
mainLabel.Text = text;
mainLabel.Frame = new CGRect(5, 5, ContentView.Bounds.Width, 26);
}
}

Unity prefab acting weird?

I wrote some code that allows the user to instantiate objects in editor mode by loading the input images in streaming assets and then creating objects using these images.
This has worked well, the problem is when I try to create a prefab with one of these objects. For some reason, the image is not saved in the prefab, and so when I load that prefab, I get white images instead of the ones that were in the original gameobject.
Update: It turns out that my background screen is actually working correctly, but none of the other gameobjects are. So I am not sure what is wrong and why it is only working for some objects but not the other.
here is my code:
public class PlacementObject : MonoBehaviour
{
private loadbackgroundImages backgroundReference;
public Sprite mouseShape;
private Image mouseSprite;
private RectTransform mouseMovement;
public Canvas myCanvas;
private int currentState = 0;
private bool canMove = true;
public List<Texture2D> allButtons;
private List<Sprite> allButtonsSprite;
private List<Sprite> allUISprites;
private List<Texture2D> allUIElements;
private int uiButtonStates = 0;
private int uiElementStates = 0;
public GameObject afterImport;
private GameObject clonedObject;
public GameObject child;
public GameObject objectToBeExported;
private bool isLoading = true;
private bool isfinishedUploading;
private Vector2 defaultSize;
// Use this for initialization
void Start()
{
allUIElements = new List<Texture2D>();
allButtons = new List<Texture2D>();
var info = new DirectoryInfo(Application.streamingAssetsPath + "/" + "UIButtons");
var fileInfo = info.GetFiles();
foreach (FileInfo file in fileInfo)
{
if (file.Extension == ".png" || file.Extension == ".jpg")
{
StartCoroutine(uploadButtonImages(System.IO.Path.Combine("file:///" + Application.streamingAssetsPath, "UIButtons/" + file.Name)));
}
}
var info2 = new DirectoryInfo(Application.streamingAssetsPath + "/" + "UIElements");
var fileInfo2 = info2.GetFiles();
foreach (FileInfo file2 in fileInfo2)
{
if (file2.Extension == ".png" || file2.Extension == ".jpg")
{
StartCoroutine(uploadUiImages(System.IO.Path.Combine("file:///" + Application.streamingAssetsPath, "UIElements/" + file2.Name)));
}
}
allButtonsSprite = new List<Sprite>();
allUISprites = new List<Sprite>();
//createSpritesForButtons(allButtons);
// createSpritesForElements(allUIElements);
mouseSprite = GetComponent<Image>();
mouseSprite.sprite = mouseShape;
mouseMovement = GetComponent<RectTransform>();
backgroundReference = FindObjectOfType<loadbackgroundImages>();
isfinishedUploading = true;
defaultSize = mouseMovement.sizeDelta;
}
// Update is called once per frame
void Update()
{
print(isLoading);
if (isfinishedUploading && backgroundReference.isfinished)
{
isLoading = false;
}
Cursor.visible = false;
transform.position = Input.mousePosition;
Vector2 pos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(myCanvas.transform as RectTransform, Input.mousePosition, myCanvas.worldCamera, out pos);
transform.position = myCanvas.transform.TransformPoint(pos);
if (isLoading == false)
{
if (currentState == 2)
{
mouseSprite.sprite = allUISprites[uiElementStates];
}
if (currentState == 1)
{
mouseSprite.sprite = allButtonsSprite[uiButtonStates];
}
if (Input.GetKeyDown(KeyCode.V))
{
currentState = 0;
mouseSprite.sprite = mouseShape;
mouseMovement.sizeDelta = defaultSize;
}
else if (Input.GetKeyDown(KeyCode.B))
{
currentState = 1;
}
else if (Input.GetKeyDown(KeyCode.N))
{
currentState = 2;
}
if (Input.GetMouseButtonDown(0))
{
placeObject();
}
if (Input.GetAxis("Horizontal") > 0 && canMove)
{
canMove = false;
if (currentState == 0)
{
changeBackgroundNext();
}
else if (currentState == 1)
{
changeButtonNext();
}
else if (currentState == 2)
{
changeElementNext();
}
}
if (Input.GetMouseButton(1))
{
rotateObject();
}
if (Input.GetAxis("Vertical") < 0)
{
if (currentState == 1 || currentState == 2)
{
mouseMovement.sizeDelta -= new Vector2(1, 1);
}
}
if (Input.GetAxis("Vertical") > 0)
{
if (currentState == 1 || currentState == 2)
{
mouseMovement.sizeDelta += new Vector2(1, 1);
}
}
if (Input.GetAxis("Horizontal") < 0 && canMove)
{
canMove = false;
if (currentState == 0)
{
changeBackgroundPrev();
}
else if (currentState == 1)
{
changeButtonPrev();
}
else if (currentState == 2)
{
changeElementPrev();
}
}
if (Input.GetAxis("Horizontal") == 0)
{
canMove = true;
}
if (Input.GetKeyDown(KeyCode.Space))
{
var newBackgroundSprite = backgroundReference.allSprites[backgroundReference.imageIndex];
backgroundReference.imageReference.sprite = newBackgroundSprite;
// exportObject();
// importObject();
#if UNITY_EDITOR
var prefab = PrefabUtility.CreatePrefab( "Assets/Resources/Image.prefab", FindObjectOfType<loadbackgroundImages>().gameObject);
AssetDatabase.Refresh();
#endif
}
}
}
void rotateObject()
{
if (currentState == 1 || currentState == 2)
mouseMovement.eulerAngles += new Vector3(0, 0, 1);
}
private void exportObject()
{
UIData saveData = new UIData();
saveData.inputObject = objectToBeExported;
//Save data from PlayerInfo to a file named players
DataSaver.saveData(saveData, "UI");
}
public void importObject()
{
UIData loadedData = DataSaver.loadData<UIData>("UI");
if (loadedData == null)
{
return;
}
//Display loaded Data
Debug.Log("Life: " + loadedData.inputObject);
afterImport = loadedData.inputObject;
}
private void changeBackgroundNext()
{
backgroundReference.imageIndex++;
if (backgroundReference.imageIndex >= backgroundReference.allSprites.Count)
{
backgroundReference.imageIndex = 0;
}
}
private void changeButtonNext()
{
uiButtonStates++;
if (uiButtonStates >= allButtonsSprite.Count)
{
uiButtonStates = 0;
}
}
private void changeElementNext()
{
uiElementStates++;
if (uiElementStates >= allUISprites.Count)
{
uiElementStates = 0;
}
}
private void changeElementPrev()
{
uiElementStates--;
if (uiElementStates < 0)
{
uiElementStates = allUISprites.Count - 1;
}
}
private void changeButtonPrev()
{
uiButtonStates--;
if (uiButtonStates < 0)
{
uiButtonStates = allButtonsSprite.Count - 1;
}
}
private void changeBackgroundPrev()
{
backgroundReference.imageIndex--;
if (backgroundReference.imageIndex < 0)
{
backgroundReference.imageIndex = backgroundReference.allSprites.Count - 1;
}
}
IEnumerator uploadButtonImages(string url)
{
WWW www = new WWW(url);
yield return www;
if (www != null)
{
allButtons.Add(www.texture);
allButtonsSprite.Add(Sprite.Create(www.texture, new Rect(0, 0, www.texture.width, www.texture.height), new Vector2(0.5f, 0.5f)));
}
}
private void createSpritesForButtons(List<Texture2D> allTextures)
{
for (int i = 0; i < allTextures.Count; i++)
{
Sprite tempSprite = Sprite.Create(allTextures[i], new Rect(0, 0, allTextures[i].width, allTextures[i].height), new Vector2(0.5f, 0.5f));
tempSprite.name = "Button" + i;
allButtonsSprite.Add(tempSprite);
}
}
IEnumerator uploadUiImages(string url)
{
WWW www = new WWW(url);
yield return www;
print(url);
if (www != null)
{
allUIElements.Add(www.texture);
allUISprites.Add(Sprite.Create(www.texture, new Rect(0, 0, www.texture.width, www.texture.height), new Vector2(0.5f, 0.5f)));
}
}
private void createSpritesForElements(List<Texture2D> allTextures)
{
for (int i = 0; i < allTextures.Count; i++)
{
Sprite tempSprite = Sprite.Create(allTextures[i], new Rect(0, 0, allTextures[i].width, allTextures[i].height), new Vector2(0.5f, 0.5f));
tempSprite.name = "" + i;
allUISprites.Add(tempSprite);
}
}
private void placeObject()
{
if (currentState == 1)
{
var gameObject = Instantiate(child, transform.position, Quaternion.Euler(mouseMovement.eulerAngles.x, mouseMovement.eulerAngles.y, mouseMovement.eulerAngles.z), backgroundReference.transform);
gameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(mouseMovement.sizeDelta.x, mouseMovement.sizeDelta.y);
var newSprite = allButtonsSprite[uiButtonStates];
gameObject.GetComponent<Image>().sprite = newSprite;
gameObject.AddComponent<Button>();
}
if (currentState == 2)
{
var gameObject = Instantiate(child, transform.position, Quaternion.Euler(mouseMovement.eulerAngles.x, mouseMovement.eulerAngles.y, mouseMovement.eulerAngles.z), backgroundReference.transform);
gameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(mouseMovement.sizeDelta.x, mouseMovement.sizeDelta.y);
var newSprite = allUISprites[uiElementStates];
gameObject.GetComponent<Image>().sprite = newSprite;
}
}
}
When you're changing some object's state via an inspector script you have to tell Unity, that you've done some changes, otherwise it doesn't know that something has happened to objects at the scene. And according to the information about changes on your scene (also when you change it manually, not by script) Unity serializes all data on your scene to save all the information. And when you load scene (doesn't matter in editor or in play mode) Unity deserializes all the objects on scene to show you. As far as serializing/deserializng object is rather expensive operation Unity only does it when it's really necessary - in case of saving scene/object it's only performed when it knows that there're some changes that needs to be saved.
The actual solution of your problem depends on Unity version you're using. Try reading this post. Such things as Undo and MarkAllScenesDirty should help you. For older versions of Unity EditorUtility.SetDirty should help.
So as people pointed out like Vmchar, when you save the prefab using code. it gets saved using the initial state without any of the stuff that got loaded to it during runtime.
I found out a solution for this though, all you need to do is make a script that would save the image by serializing it in streamingassets (plenty of tutorials online on how to serialize image), and then loading it using www stream when needed in the other scene.

android - how to catch touch event like game: World Search

I have a game like WorldSearch on Store, I tried using this solution:
I created matrix by array of TextView and added TouchEvent on each TextView. Then I caught event by MOTION.UP, MOTION.DOWN. When I touched on a TextView and dragged it, although it went thought other TextViews but I just could get event of first TextView.
Here is code:
private void createMetrix(){
// amound of item in a row and column
int itemNum = 10;
// calculate size of item
ScreenDimension screenDimension = Utilities.getFinalScreenDimension(this);
int itemSize = screenDimension.screenWidth / 10;
// mContentLinear has VERTICAL orientation
// then adding children linear layouts, these layout has HORIZONTAL orientation
for(int i = 0; i < itemNum; i++) {
LinearLayout theItemLayout = createHorizontalLayout(itemNum, itemSize, i);
mContentLinear.addView(theItemLayout);
}
}
private LinearLayout createHorizontalLayout(int itemNum, int itemSize, int row) {
LinearLayout theLinear = new LinearLayout(this);
theLinear.setOrientation(LinearLayout.HORIZONTAL);
theLinear.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, itemSize));
for(int i = 0; i < itemNum; i++){
// add item metrix into linear layout having HORIZONTAL orientation
TextView itemTxt = createItemMatrix(itemSize, row, i);
theLinear.addView(itemTxt);
}
return theLinear;
}
private TextView createItemMatrix(int itemSize, int row, int column) {
TextView theItemTxt = new TextView(this);
theItemTxt.setWidth(itemSize);
theItemTxt.setHeight(itemSize);
theItemTxt.setTextSize(13);
theItemTxt.setGravity(Gravity.CENTER);
theItemTxt.setText("A" + row + "" + column);
String tag = row + "|" + column;
theItemTxt.setTag(tag);
theItemTxt.setOnTouchListener(mOnTouchListener);
return theItemTxt;
}
// Listener
private View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
private Rect rect;
#Override
public boolean onTouch(View v, MotionEvent event) {
if (v == null) return true;
TextView itemTxt = (TextView)v;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
Log.d("TEXT", "MOVE DOWN: " + itemTxt.getText().toString());
return true;
case MotionEvent.ACTION_UP:
if (rect != null
&& !rect.contains(v.getLeft() + (int) event.getX(),
v.getTop() + (int) event.getY())) {
// The motion event was outside of the view, handle this as a non-click event
return true;
}
// The view was clicked.
Log.d("TEXT", "MOVE ON: " + itemTxt.getText().toString());
// TODO: do stuff
return true;
case MotionEvent.ACTION_MOVE:
Log.d("TEXT", "MOVE OUT: " + itemTxt.getText().toString());
return true;
default:
return true;
}
}
};
Does someone have any ideas on this case?
Thanks,
Ryan

Resources