TMSFMXNativeUICollectionView chnge size of control

Hi,

I placed an TTMSFMXNativeUICollectionViewTemplateImageView inside a TTMSFMXNativeUICollectionView, with a small size.

When selecting the item I want the Image to get bigger in size.
When selecting another image I want the previously selected image to get small again.

AllowsMultipleSelection is set to false.


procedure TFCollectionView.FormCreate(Sender: TObject);
begin

  // Set two Items per Row
  // Set Item.Width  to half of CollectionView.Width
  // Set Item.Height to half the Item.Width
  TMSFMXNativeUICollectionView1.Options.ItemWidth       := TMSFMXNativeUICollectionView1.Width/2 - 6;
  TMSFMXNativeUICollectionView1.Options.ItemHeight      := TMSFMXNativeUICollectionView1.Width/4;

  // Set Image to half the Itemheight, square
  TMSFMXNativeUICollectionViewTemplateImageView1.x      := 0;
  TMSFMXNativeUICollectionViewTemplateImageView1.y      := 0;
  TMSFMXNativeUICollectionViewTemplateImageView1.Height := TMSFMXNativeUICollectionView1.Options.ItemHeight/2;
  TMSFMXNativeUICollectionViewTemplateImageView1.Width  := TMSFMXNativeUICollectionView1.Options.ItemHeight/2;

  TMSFMXNativeUICollectionViewTemplateLabel1.X          := TMSFMXNativeUICollectionViewTemplateImageView1.Width + 6;
  TMSFMXNativeUICollectionViewTemplateLabel1.y          := 0;


end;

procedure TFCollectionView.TMSFMXNativeUICollectionView1DidDeselectItem(Sender: TObject; ASection, ARow: Integer);
var
  aControl : TTMSFMXNativeUICollectionViewTemplateControl;
begin
  // when Item is deselected set image size to half height of Item
  aControl := TMSFMXNativeUICollectionView1.GetItemTemplateControl(ASection, ARow, 1);
  if Assigned(aControl) and IsImageView(aControl) then begin
    AsImageView(aControl).Height := TMSFMXNativeUICollectionView1.Options.ItemHeight / 2;
    AsImageView(aControl).Width  := TMSFMXNativeUICollectionView1.Options.ItemHeight / 2;
  end;
end;

procedure TFCollectionView.TMSFMXNativeUICollectionView1DidselectItem(Sender: TObject; ASection, ARow: Integer);
var
  aControl : TTMSFMXNativeUICollectionViewTemplateControl;
begin
  // when Item is selected set image size to full height of Item
  aControl := TMSFMXNativeUICollectionView1.GetItemTemplateControl(ASection, ARow, 1);
  if Assigned(aControl) and IsImageView(aControl) then begin
    AsImageView(aControl).height := TMSFMXNativeUICollectionView1.Options.ItemHeight;
    AsImageView(aControl).width  := TMSFMXNativeUICollectionView1.Options.ItemHeight;
  end;
end;

when running the app various images are small, others are big ...
What am I doing wrong?

Thanks in advance,
Dietrich

Hi, 


The template cannot be manipulated, as this is the same for all items. Internally a clone is made from the template, so if you change the template, all the items will change as well. In the CollectionView demo, we show (via animation) a detail view. This is based on the item itself, and not on the template. You can use this technique to show a larger version of the image view. The demo is included in the distribution and can be found under ..\public documents\tmssoftware\TMS iCL Demos

is it not possible to access the clone?
I also want to set a button to visible := false, if the item is not selected for a more simple design

Thanks in advance,
Dietrich

Accessing the clone is demonstrated in the sample.

Cool,
Thanks!

I still can't find my way.
This is how far I got:

procedure TForm20.TMSFMXNativeUICollectionView1DidDeselectItem(Sender: TObject; ASection, ARow: Integer);
var
  c: UIcollectionviewCell;
  i: NSIndexPath;
begin
  i := TNSIndexPath.Wrap(TNSIndexPath.OCClass.indexPathForRow(ARow, ASection));
  c := TMSFMXNativeUICollectionView1.CollectionView.cellForItemAtIndexPath(i);
  if Assigned(c) then begin
    // Need help for making Image smaller:
    //... image.SetBounds(...)
  end;
end;

procedure TForm20.TMSFMXNativeUICollectionView1DidselectItem(Sender: TObject; ASection, ARow: Integer);
var
  c: UIcollectionviewCell;
  i: NSIndexPath;
begin
  i := TNSIndexPath.Wrap(TNSIndexPath.OCClass.indexPathForRow(ARow, ASection));
  c := TMSFMXNativeUICollectionView1.CollectionView.cellForItemAtIndexPath(i);
  if Assigned(c) then begin
    // need help for making Image larger:
    //... image.SetBounds(...)
  end;
end;

Hi, 


Did you take a look at the code in the demo? The code demonstrates how to access subelements from the cell view

procedure TForm1130.OpenDetail(ASection, ARow: Integer);
var
  a, av: NSString;
  c: UIcollectionviewCell;
  idx: NSIndexPath;
  fr: NSRect;
  ct: TCity;
begin
  idx := TNSIndexPath.Wrap(TNSIndexPath.OCClass.indexPathForRow(ARow, ASection));
  c := CityTrip.CollectionView.cellForItemAtIndexPath(idx);
  if Assigned(c) then
  begin
    ct := FContinents[ASection].Cities[ARow];
    DetailImage.BitmapFile := ExtractFilePath(ParamStr(0)) + ct.Image;
    DetailTitle.Text := ct.Title;
    DetailDescription.Text := ct.Description;
    DetailRating.BitmapFile := ExtractFilePath(ParamStr(0)) + ct.Rating;
    DetailPrice.Text := ct.Price;

    FSaveSection := ASection;
    FSaveRow := ARow;
    FSaveCellFrame := c.frame;
    fr := c.frame;
    fr.origin.x := fr.origin.x - CityTrip.CollectionView.contentOffset.x;
    fr.origin.y := fr.origin.y - CityTrip.CollectionView.contentOffset.y;
    DetailView.View.setFrame(fr);

    fr := FSaveDetailFrame;
    fr.origin.x := fr.origin.x + CityTrip.CollectionView.contentOffset.x;
    fr.origin.y := fr.origin.y + CityTrip.CollectionView.contentOffset.y;


    a := NSStr('CellAnimation');
    TUIView.OCClass.beginAnimations((a as ILocalObject).GetObjectID, nil);
    TUIView.OCClass.setAnimationCurve(UIViewAnimationCurveEaseOut);
    TUIView.OCClass.setAnimationTransition(UIViewAnimationTransitionFlipFromLeft, c, True);
    TUIView.OCClass.setAnimationDuration(Anim);
    c.setFrame(fr);
    c.setAlpha(0);
    TUIView.OCClass.commitAnimations;

    av := NSStr('ViewAnimation');
    TUIView.OCClass.beginAnimations((av as ILocalObject).GetObjectID, nil);
    TUIView.OCClass.setAnimationCurve(UIViewAnimationCurveEaseOut);
    TUIView.OCClass.setAnimationTransition(UIViewAnimationTransitionFlipFromLeft, DetailView.View, True);
    TUIView.OCClass.setAnimationDuration(Anim);
    DetailView.View.setAlpha(1);
    DetailView.View.setFrame(FSaveDetailFrame);
    TUIView.OCClass.commitAnimations;

    av := NSStr('OverLayAnimation');
    TUIView.OCClass.beginAnimations((av as ILocalObject).GetObjectID, nil);
    TUIView.OCClass.setAnimationCurve(UIViewAnimationCurveEaseOut);
    TUIView.OCClass.setAnimationDuration(Anim);
    Overlay.View.setAlpha(0.85);
    TUIView.OCClass.commitAnimations;
  end;
end;

sure,
but I want to access the CityTrip.ItemImage not the DetailView.DetailImage from the CollectionView-Example ...

Please show how.

Thanks,
Dietrich

Perhaps you can try with the following code


var
  c: UIcollectionviewCell;
  idx: NSIndexPath;
  I: Integer;
  v: UIView;
  p: Pointer;
  img: UIImageView;
begin
  idx := TNSIndexPath.Wrap(TNSIndexPath.OCClass.indexPathForRow(ARow, ASection));
  c := CityTrip.CollectionView.cellForItemAtIndexPath(idx);
  if Assigned(c) then
  begin
    for I := 0 to c.subviews.count - 1 do
    begin
      p := c.subviews.objectAtIndex(I);
      v := TUIView.Wrap(p);
      if v.isKindOfClass(objc_getClass('UIImageView')) then
      begin
        img := TUIImageView.Wrap(p);
      end;
    end;
  end;

Hi,
I extended the code with "contentview" to reach the UIImageView.

When selecting the cell, the imageView changes the size correctly.

But
when I scroll down the collection, several cells are resized although I
never selected them (They are resized periodically ...).

Why?

I
just want the user to select a cell which resizes the image contained
in that cell. All other images should stay in original size.

procedure TForm1.TMSFMXNativeUICollectionView1DidselectItem(Sender: TObject; ASection, ARow: Integer);
var
  c   : UIcollectionviewCell;
  idx : NSIndexPath;
  i   : Integer;
  v   : UIView;
  p   : Pointer;
  img : UIImageView;
  f   : NSRect;
begin

  idx := TNSIndexPath.Wrap(TNSIndexPath.OCClass.indexPathForRow(ARow, ASection));
  c   := TMSFMXNativeUICollectionView1.CollectionView.cellForItemAtIndexPath(idx);

  if Assigned(c) then begin

    for i := 0 to c.contentview.subviews.count - 1 do begin

      p := c.contentview.subviews.objectAtIndex(i);
      v := TUIView.Wrap(p);

      if v.isKindOfClass(objc_getClass('UIImageView')) then begin

        f := TMSFMXNativeUICollectionViewTemplateImageView1.ImageView.frame;
        f.size.width := TMSFMXNativeUICollectionViewTemplateImageView1.ImageView.frame.size.width + 100;
        img := TUIImageView.Wrap(p);
        img.setFrame(f);

      end;
    end;
  end;
end;





Hi, 


Note that the collection view is recycling it's cells for performance reasons, so when scrolling, the cell you manipulated might be recycled somewhere else. To solve this issues, you'll need to use a different approach. 

You should store a value for a specific section/row in the OnDidSelectItem event. Afterwards, call reloadData, and use this value for checking if the image needs to be enlarged. Then the code that retrieves the subview should be placed in the OnApplyItemValue event:

Here is some modified code that should accomplish this behaviour. Please note that this is only used for 1 item



procedure TForm41.TMSFMXNativeUICollectionView1ApplyItemValue(Sender: TObject;
  AControl: TTMSFMXNativeUICollectionViewTemplateControl; ASection,
  ARow: Integer);
var
  c   : UIcollectionviewCell;
  idx : NSIndexPath;
  i   : Integer;
  v   : UIView;
  p   : Pointer;
  img : UIImageView;
  f   : NSRect;
begin
  if (FSection = ASection) and (FRow = ARow) then
  begin
    idx := TNSIndexPath.Wrap(TNSIndexPath.OCClass.indexPathForRow(ARow, ASection));
    c := TMSFMXNativeUICollectionView1.CollectionView.cellForItemAtIndexPath(idx);


    if Assigned(c) then
    begin
      for i := 0 to c.contentview.subviews.count - 1 do
      begin
        p := c.contentview.subviews.objectAtIndex(i);
        v := TUIView.Wrap(p);


        if v.isKindOfClass(objc_getClass('UIImageView')) then
        begin
          f := TMSFMXNativeUICollectionViewTemplateImageView1.ImageView.frame;
          f.size.width := TMSFMXNativeUICollectionViewTemplateImageView1.ImageView.frame.size.width + 100;
          img := TUIImageView.Wrap(p);
          img.setFrame(f);
        end;
      end;
    end;
end;


procedure TForm41.TMSFMXNativeUICollectionView1DidselectItem(Sender: TObject;
  ASection, ARow: Integer);
begin
  FSection := ASection;
  FRow := ARow;
  TMSFMXNativeUICollectionView1.ReloadData;
end;


Hi,

thanks for fast answer.

I tried this approach but the problem is that c is never assigned:


Can you try the following instead



procedure TForm1.CityTripApplyItemValue(Sender: TObject;
  AControl: TTMSFMXNativeUICollectionViewTemplateControl; ASection,
  ARow: Integer);
begin
  if IsImageView(AControl) and (ASection = FSection) and (ARow = FRow) then
    AsImageView(AControl).Width := 100;
end;

OK!
I modified your idea and it works!

procedure TForm1.TMSFMXNativeUICollectionView1ApplyItemValue(Sender: TObject; AControl: TTMSFMXNativeUICollectionViewTemplateControl; ASection, ARow: Integer);
begin
  if IsImageView(AControl) then begin
    if (ASection = FSection) and (ARow = FRow) then
      AControl.Width  := 150
    else
      AControl.Width  := 250;
    AsImageView(AControl).ImageFile := TPath.combine(TPath.GetDocumentsPath, GetImageName(ASection, ARow));
  end;
end;

procedure TForm1.TMSFMXNativeUICollectionView1DidDeSelectItem(Sender: TObject; ASection, ARow: Integer);
begin
  FRow     := -1;
  FSection := -1;
  TMSFMXNativeUICollectionView1.ReloadItem(ASection, ARow);
end;

procedure TForm1.TMSFMXNativeUICollectionView1DidSelectItem(Sender: TObject; ASection, ARow: Integer);
begin
  FRow     := ARow;
  FSection := ASection;
  TMSFMXNativeUICollectionView1.ReloadItem(ASection, ARow);
end;

Thanks a lot!
Dietrich

Thank you for your confirmation.