eBay / NMessenger

A fast, lightweight messenger component built on AsyncDisplaykit and written in Swift
Other
2.42k stars 272 forks source link

[question] How to place the avatar on top of the MessageNode bubble? #115

Open dodikk opened 7 years ago

dodikk commented 7 years ago

By default, the avatar's position is on the bottom of the bubble (see the screenshot). 1-bottom


Is it possible to render it in the upper part of the MessageNode? I have not found any appropriate methods. Which class should I use if I'm looking at a wrong one?

dodikk commented 7 years ago

That's what I'm trying to build :


2-expected

atainter commented 7 years ago

I don't have a property exposed for changing the position of the message node. I can add one in a couple days. As far as what you're trying to build -- I would recommend creating a custom content node (which has a timestamp and the text) and a custom bubble.

dodikk commented 7 years ago

I would recommend creating a custom content node (which has a timestamp and the test) and a custom bubble.

@atainter , thanks for the reply. Should I consider usual AsyncDisplayKit tutorials and docs? Or is there anything NMessenger specific I should know implementing this? Are there any NMessenger related guides available?

dodikk commented 7 years ago

I don't have a property exposed for changing the position of the message node. I can add one in a couple days.

Thanks, this would be useful, I guess. I'll try to follow the "custom node" approach you've suggested.

dodikk commented 7 years ago

@atainter , I think, I do need the "avatar position fix" heavily.

It would be cool if the bubble could somehow know the Y position of the avatar (in bubble's coordinates) at the moment of sizeToBounds invocation in order to place the "triangle" properly.

dodikk commented 7 years ago

So far I'm trying to rewrite a copy of DefaultBubble so that its stroke would be using comething like this code

P.S. Credits to the SO topic

atainter commented 7 years ago

Should I consider usual AsyncDisplayKit tutorials and docs? Or is there anything NMessenger specific I should know implementing this? Are there any NMessenger related guides available?

I would look over TextContentNode or ImageContentNode to get an idea of how to subclass content node. However, yes, it is mainly ASDK stuff.

atainter commented 7 years ago

It would be cool if the bubble could somehow know the Y position of the avatar (in bubble's coordinates) at the moment of sizeToBounds invocation in order to place the "triangle" properly.

Let me think about how to implement this. If I can't think of an elegant solution, you might be limited to TOP or BOTTOM positioning. The issue is that it interferes with the MessageGroup animations.

dodikk commented 7 years ago

It would be cool if the bubble could somehow know the Y position of the avatar (in bubble's coordinates) at the moment of sizeToBounds invocation in order to place the "triangle" properly.

Let me think about how to implement this. If I can't think of an elegant solution, you might be limited to TOP or BOTTOM positioning. The issue is that it interferes with the MessageGroup animations.

Cool. Thanks.

dodikk commented 7 years ago

So far, I'm trying to stick with your TextContentNode and tweak the bubble only. I've managed to do this (the timestamp is prepended to the TextContentNode.textMessageString which is a bit "unfair").

simulator screen shot apr 6 2017 10 43 21 am

P.S. I think I'll write a tutorial after getting the thing done. Thanks for helping with my struggles.

dodikk commented 7 years ago

I think I'll be able to change the path (bubble shape) according to the designs. The only thing remaining is the avatar position.


you might be limited to TOP or BOTTOM positioning

I think I'll be able to hard code some magic constants so that a triangle looks ok. But precise "avatar center" position would be so helpful.

dodikk commented 7 years ago

So, I've managed to change the shape but the bubbles are too close to each other right now. The NMessengerViewController.messagePadding does not seem to affect that.

    override func viewDidLoad()
    {
        super.viewDidLoad()

        precondition(nil != self.controller)
        self.controller?.delegate = self

        super.sharedBubbleConfiguration = self.vhBubbleConfig

        // this value seems to be ignored
        super.messagePadding = UIEdgeInsets(top: 30, left: 0, bottom: 30, right: 0)

        self.messengerView.doesBatchFetch = true
        self.controller?.getInitialHistoryAsync()
    }

Here is my code for bubble and bubble configuration sub-classes https://gist.github.com/dodikk/c0f0bb7c00380e9fe064e226f3909505

dodikk commented 7 years ago

simulator screen shot apr 6 2017 12 17 43 pm

dodikk commented 7 years ago

Also, I have an issue with glow effect. My configuration of layer shadows does not seem to take any effect.

open override func createLayer() {

       ... // the existing code
       ... 

        // glow effect attempt
        //
        self.maskLayer.shadowPath = self.path
        self.maskLayer.shadowOffset = CGSize(width: 0, height: 0)
        self.maskLayer.shadowColor = self.bubbleBorderColor.cgColor
        self.maskLayer.shadowRadius = 10

        self.layer.shadowPath = self.path
        self.layer.shadowOffset = CGSize(width: 0, height: 0)
        self.layer.shadowColor = self.bubbleBorderColor.cgColor
        self.layer.shadowRadius = 10

A similar technique works fine for UIView.drawRect

    static const CGFloat SHADOW_BLUR = 8;

    // http://stackoverflow.com/questions/10024543/draw-lines-with-glow-effect-in-ipad-app
    //
    //Set the shadow in your graphics context to have a zero size offset, a blur of around 6-10 (change according to taste) and the same colour as your stroke colour. This will give all subsequent drawing a glow effect. The command is
    //
    //
    CGContextSetShadowWithColor(context, CGSizeMake(0, 0), SHADOW_BLUR, strokeColor.CGColor);
dodikk commented 7 years ago

My configuration of layer shadows does not seem to take any effect.

Solved by adding shadowOpacity

self.maskLayer.shadowOpacity = 1
self.maskLayer.masksToBounds = false
dodikk commented 7 years ago

But now it's clipped on both top and the bottom. Setting self.clipsToBounds = false on TextContentNode does not help much.

simulator screen shot apr 6 2017 1 38 38 pm

atainter commented 7 years ago

How are you adding messages to the messenger? MessagePadding should work if you set it directly on the MessageNode. I'll look into that value not being honored in the ViewController. self.clipsToBounds = false should be set on the MessageNode once you've added padding (now that I think about it, that value should actually be called margin)

dodikk commented 7 years ago

How are you adding messages to the messenger?

@atainter , I've added my NMessengerViewController subclass to the gist. https://gist.github.com/dodikk/c0f0bb7c00380e9fe064e226f3909505

MessagePadding should work if you set it directly on the MessageNode.

Thanks. I'll try this out tomorrow.

dodikk commented 7 years ago

MessagePadding should work if you set it directly on the MessageNode.

It does not work for me. Nothing happens even when I change the default "insets" value of the node

open class TextContentNode: ContentNode,ASTextNodeDelegate {

    // MARK: Public Variables
    /** Insets for the node */
    open var insets = UIEdgeInsets(top: 30, left: 10, bottom: 30, right: 10) {
        didSet {
            setNeedsLayout()
        }
    }
dodikk commented 7 years ago

self.clipsToBounds = false should be set on the MessageNode

No luck either. I've added this to the very end of my buildNodeForTextMessage code.

contentNode.clipsToBounds = false
contentNode.textMessageNode.clipsToBounds = false
dodikk commented 7 years ago

@atainter , How is your progress implementing the avatar positioning thing going on?

I still hope of getting some help but I might have to implement it myself due to my deadline. Am I supposed to rewrite some of the MessageNode.layoutSpecThatFits code in this case or is there a better customization point to look at?

P.S. Thanks again both for the library and for your replies.

Alond commented 7 years ago

@dodikk , to put avatar to top layoutSpecs = ASStackLayoutSpec(direction: .horizontal, spacing: 0, justifyContent: justifyLocation, alignItems: .start, children: cellOrientation)

dodikk commented 7 years ago

@Alond , thanks for the reply. I've figured that out already and I've submitted a pull request that adds the corresponding tweak to NMessenger. Waiting for @atainter to approve and mere it to the upstream.