Home > JavaScript, Object Pascal, Smart Mobile Studio > Fixed Header in Smart Applications

Fixed Header in Smart Applications

Smart Mobile Studio gives you a lot of really cool visual controls to play with. One of them is a header control (also called a navigation panel by some) that traditionally show and hide it’s buttons (back and next) in response to form navigation.

One question that many people have asked is: how can I make a header that remains fixed and doesnt scroll with the forms? So no matter what form I navigate to, the header remains in place. Preferably easily accessed.

The Visual Application

Smart Visual Applications are more than just forms and buttons. The first thing that is created when you run a visual Smart Application, is naturally an instance of TApplication; this in turn creates a display control, and inside that again there is something called a “viewport”. Forms are always created inside the viewport.

If you are wondering why on earth we use two nested containers like this, that has to do with scrolling and keeping our controls isolated in one place. Forms are positioned horizontally inside the viewport. So whenever you are moving from Form1 to Form2, depending on the scroll-effect you have picked, the second form is lined up either before or after the current form. We then execute a CSS3 animation that smoothly scrolls the new form into view, or the previous form out of view – depending on how you look at it.

The display

The root display control, TW3Display, has only one job; and that is to house the view control. It also contains code to layout child controls vertically. Since there is typically only one control present – that means you don’t notice much of what TW3Display does.

The “trick” to a static header that remains un-affected by forms, is simply to create the header control with “Application.Display” as the parent. That is all you have to do. You could also create it on Application.Display.View, but then it would cause problems with scrolling. My point for mentioning that is to underline how the RTL has no special rules for it’s structure. All visual entities that make up your Smart Pascal application follow the same laws and are subject to the same rules as TW3Button or TW3Label might be.

Creating controls that don’t attach to a form

The vertical layout that TW3Display does automatically is very simple. It sorts the child elements based on their Y position and places them directly after each other. This means that all you have to do is create the header and then make sure you give it a negative Y position, and it will always remain fixed on top of the Viewport and it’s forms.

TW3Application has a virtual method called ApplicationStarting() that is perfect for what we want to achieve. As the name says this method fires when the application is starting, so this is perfect for creating controls that don’t attach to a form. It also has an accompanying ApplicationClosing() method where we can release the control.

So let’s start by creating our control. Each visual application has a “unit1” that is created automatically. This contains your application object. While TApplication is a bit anonymous under Delphi or Lazarus, under Smart it serves a more central role. It’s the place you expose global values that should be usable throughout the entire program.

unit Unit1;

interface

uses
  Pseudo.CreateForms, // auto-generated unit that creates forms during startup
  System.Types, SmartCL.System, SmartCL.Components, SmartCL.Forms,
  SmartCL.Application,
  SmartCL.Controls.Header,
  Form1;

type

  TApplication  = class(TW3CustomApplication)
  private
    FHeader:  TW3HeaderControl;
  protected
    procedure ApplicationStarting; override;
    procedure ApplicationClosing; override;
  public
    property  Header: TW3HeaderControl read FHeader;
  end;

implementation

procedure TApplication.ApplicationStarting;
begin
  inherited;
  FHeader := TW3HeaderControl.Create(Display);
  FHeader.SetBounds(0, -10, 100, 46);
end;

procedure TApplication.ApplicationClosing;
begin
  FHeader.free;
  inherited;
end;

end.

Let’s compile and see what we got so far!

static_01

As expected we now have a header outside the form region

Global access

SmartCL, which is the namespace (a collection of units organized under one name) where all visual, DOM based classes live, have a global function for getting the Application object. This is simply Application() and you have probably used it many times.

What is not so well-known is that Application() returns a stock TCustomApplication instance. In other words, if you inspect the instance you will find none of the properties you have defined in TApplication. This is because TApplication is unknown until the application is executed. So in order to access your actual application object, you need to typecast; like I do here:

procedure TForm1.InitializeObject;
begin
  inherited;
  {$I 'Form1:impl'}
  var app := TApplication(Application);
  app.Header.Title.Caption := 'This is my header';
end;

Let’s have a look at the result (note: I added a label as well, just so you don’t think you missed something):

static_02

Now this approach works fine for many types of objects. I tend to isolate my database instance there, static header, global storage — all of it can be neatly exposed via TApplication. Fast, simple and efficient.

The final step

The initial state for the static header should be that both buttons are hidden by default. So when you start the application it just shows a title, nothing more.

When you click something that cause navigation to form2 (or some other second form), the back-button should become visible once form2 has scrolled into view.

When the user click the back-button, the opposite should happen. The back button should be disabled while you navigate back to form1, then completely hidden once you have arrived.

I don’t think I need to demonstrate this. Obviously, if you have forms that leads to more forms – then you probably want to add a “navigation stack” to the application object – an array that holds the previously visited forms.

Then whenever someone hits the “back button” you just pop the previous form off the stack, and navigate to it.

Well, hope it helps!

 

 

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: