Problems using UIViewComponent in an iOS app

Hey folks - has anybody ever tried integrating JUCE Component objects into an Objective-C iOS app? From looking in the forums I’ve seen reference to a class called UIViewComponent. From the documentation I tried whipping something together but didn’t have any luck. The basic idea seems to be that you create a UIViewComponent derived class and then give at UIView to be hosted in.

I created a standalone example here, but it doesn’t work:

Any pointers or help greatly appreciated!

Let me make this a bit more concise:

UIViewComponent is not working under a UIView.

I want to be able to create a sophisticated JUCE Component in GeoShred (which is an iOS app written in Objjective-C)

I tried the following, and the attached example is a working demonstration. It’s a bit hard to even get something like this running because you have to create a static JUCE library. The library I am using is I think from one or two versions of JUCE back, but I need to use for my project. Now, if there is an example somewhere of how to drag the JUCE source code directly into an Objective-C project, I can consider that - actually I would like that - Anyway, here goes:

  • Create a new single window app in Objective-C

  • Rename the ViewController class ViewController.mm so
    it can be Objective C++

  • Figure out how to include a static JUCE library and the JUCE
    headers (the project I attached in the last message does this)

  • Make a simple derived class of UIViewComponent:

class MyComponent : public UIViewComponent
{
void paint(Graphics &g) overide {
DBG(“paint called”);
}

void resized() overide {
    DBG("resized called");
}

};

  • Add a pointer to this class in ViewController.mm

@interface ViewController ()
{
MyComponent *myComponent;
}
@end

  • Modify viewDidLoad in ViewController.mm like this:

-(void)viewDidLoad
{
[super viewDidLoad];
UIView *container = [[UIView alloc] initWithFrame:frame];
container.layer.backgroundColor = UIColor.greenColor.CGColor;
[self.view addSubview:container];
myComponent = new MyComponent();
myComponent->setView((__bridge void *)container);
}

  • Now you’d hope to see the paint method getting called, it never happens,
    in fact you’ll probably get a crash, unless you do the jive-ass stuff
    I did in my example to call functions on the message thread etc.

  • So try it with self.view, still no luck:

-(void)viewDidLoad
{
[super viewDidLoad];
myComponent = new MyComponent();
myComponent->setView((__bridge void *)self.view);
}

Thanks for any help in advance

  • Nick

No, you shouldn’t derive from UIViewComponent! Just add one as a member, make sure it’s visible and use setView() to pass in the native UIView that you’d like to display.

So maybe UIViewComponent is not what I need - what I want is a JUCE Component derived class to be added as a subview of an iOS UIView.

The goal is to write the UI in JUCE and insert that UI into an iOS app, not to pass a UIView subclass to be viewed in a JUCE Component.

OK I answered my own question with the help of an earlier post from 8 years ago!

#include “JuceHeader.h”

class MyJuceComponent : public Component
{
public:
Slider mySlider{“slider”};
MyJuceComponent() {
DBG(String(PRETTY_FUNCTION));
mySlider.setSliderStyle(Slider::LinearBar);
addAndMakeVisible(mySlider);
}
~MyJuceComponent() {
}
void paint (Graphics &g) override {
DBG(String(PRETTY_FUNCTION));
}

void resized() override {
    DBG(String(__PRETTY_FUNCTION__));
    mySlider.setBounds(0,0,100,50);
}

void setup() {
    setVisible(true);
}

};

@interface ViolinViewController ()
{
MyJuceComponent *mixer;
}
@end

@implementation ViolinViewController

-(void)viewDidLoad
{
[super viewDidLoad];
CGRect frame = self.view.frame;
float w = frame.size.width * 0.5;
float h = frame.size.height * 0.5;
frame.size.width = w;
frame.size.height = h;
frame.origin.x += w/2.0;
frame.origin.y += h/2.0;

mixer = new MyJuceComponent();
// https://forum.juce.com/t/drawing-a-component-insiede-a-uiview/9737/3
mixer->addToDesktop (0, (__bridge void*) self.view);
mixer->setVisible (true);
mixer->setBounds(frame.origin.x,frame.origin.y,frame.size.width,frame.size.height);

}

@end

To make your code easier to read, do one of the following:

  • Indent all the lines of your code by at least 4 spaces, or
  • Select all your code and click the button that has this symbol on it: “</>”, or
  • Put three backticks ``` before and after your code

^ This what @yfede said. If you don’t know, how to edit: click the pen icon below your post (it only appears for your own posts).