I've tried about a dozen variations on the theme of changing the camera's projection matrix after the button is drawn but before the ship is, but no matter what I do, the same things happen to both the button and the ship. So:

What is the usual libgdx way of implementing an on-screen UI that isn't transformed by the camera's projection matrix/zoom?

I think the easiest way to accomplish a hud map would be to use a second camera and overlay them. This issue has been discussed on the libgdx forums a while back and I remember someone over there posting their hud code. You may want to poke around over there and see what you come up with.

Remember, the first camera is where the background is fixed. The second one is where the ground moves. If you're wondering why the sprite moves in the stage because the secret it the ground that moves. The sprite is just walking in place since you're using a third camera. You might scrolled the second camera's ground but the HUD is still in place on third. Promise, it's true! The third camera is where the it displays the sprite in center for direction, whether he goes left or right by a little animation code, and the HUD (i.e. score, remaining lives, item used). If you need something, ask me.