I use the viewport method for clipping and if you encapsulate the code then it shouldn't make the rest of your code more complicated (at least it doesn't make it more complicated for my use case). The only real downside of the method is that you need to pass the new view to the clipping code every time the view is changed (but that only happens in one place in my code). The rest of the code doesn't need to care about how you do the clipping.
I've implemented
my code in such a way that I just need to pass the render target and states (which all my draw functions have) to the constructor of the Clipping class together with the rectangle that should be clipped (relative to the render states). As long as the clipping object exists, all draw calls are clipped. The old view will be restored when the clipping object is destroyed. It works when a custom view and viewport were already set, so it even works recursively (two clipping objects can exist at the same time and things will only be drawn inside the intersection).
Clipping clippingObject(target, states, clippingRectTopLeft, clippingRectSize);
target.draw(drawable, states); // drawing will be clipped
Drawing to a RenderTexture will probably work just as well, as long as you encapsulate the rendering so that your code doesn't need to know whether it is drawing to the screen or to an intermediate texture.