After comparing several of the answers already here I noticed that even the best of them always rely on two sheet operations — one to first copy the sheet and then a second to move it to the desired position — but none of them account for the move operation also running into the same issues with hidden sheets if the exact ordering of your sheets, including any that are hidden, is important for some reason or another.
So here's an alternative methodology to let you copy a target sheet to an exact position w.r.t. to a workbook's sheet indices regardless of which of them are hidden or not. It wraps the basic logic of Tim Williams' answer as simplified by Sat's syntax with conditionals hinging on Trevor Norman's insight that whatever Excel is doing under the hood always wants to copy the sheet to a postion immediately before a sheet that is visible:
Function CopySheetBefore(ByRef copyTarget As Worksheet, ByRef positionTarget As Worksheet) As Worksheet
Dim visibilityState As XlSheetVisibility, VeryHiddenTarget As Boolean
'record starting visibilities and reset as needed:
visibilityState = positionTarget.Visible
If Not (copyTarget Is positionTarget) Then
VeryHiddenTarget = (copyTarget.Visible = xlSheetVeryHidden)
Else
'leave it False to preclude redundant action below...\/
End If
positionTarget.Visible = xlSheetVisible
If VeryHiddenTarget Then copyTarget.Visible = xlSheetVisible
'copy sheet and set return variable:
copyTarget.Copy before:=positionTarget
Set CopySheetBefore = positionTarget.Previous
'reset visibilities to initial states:
positionTarget.Visible = visibilityState
If copyTarget Is positionTarget Then
CopySheetBefore.Visible = visibilityState
Exit Function 'to preclude redundant actions below
End If
If VeryHiddenTarget Then
copyTarget.Visible = xlSheetVeryHidden
CopySheetBefore.Visible = xlSheetVeryHidden
End If
End Function
If you know you won't ever be trying to copy a sheet that is very hidden, the function simplifies considerably to:
Function CopySheetBefore(ByRef copyTarget As Worksheet, ByRef positionTarget As Worksheet) As Worksheet
Dim visibilityState As XlSheetVisibility
'record starting visibility and reset:
visibilityState = positionTarget.Visible
positionTarget.Visible = xlSheetVisible
'copy sheet and set return variable:
copyTarget.Copy before:=positionTarget
Set CopySheetBefore = positionTarget.Previous
'reset visibility to initial state:
positionTarget.Visible = visibilityState
If copyTarget Is positionTarget Then
CopySheetBefore.Visible = visibilityState
End If
End Function
This will always insert the copied sheet to the index position immediately before the targeted position regardless of that position target's visibility or that of any other surrounding sheets.
If you're committed to thinking in terms of which sheet it should be placed after instead of before (or want to be able to insert to the last sheet index specifically), the logic is essentially the same, but the conditionals required to pull it off even though that last sheet might be hidden are a bit more complex:
Function CopySheetAfter(ByRef copyTarget As Worksheet, ByRef positionTarget As Worksheet) As Worksheet
Dim visibilityState As XlSheetVisibility
Dim CopyAfterLast as Boolean
CopyAfterLast = (positionTarget.index = sheets.count)
'record starting visibility and reset:
If CopyAfterLast Then
visibilityState = positionTarget.Visible
positionTarget.Visible = xlSheetVisible
Else
visibilityState = positionTarget.Next.Visible
positionTarget.Next.Visible = xlSheetVisible
End If
'copy sheet and set return variable:
copyTarget.Copy after:=positionTarget
Set CopySheetAfter = positionTarget.Next
'reset visibility to initial state:
If CopyAfterLast Then
positionTarget.Visible = visibilityState
Else
positionTarget.Next.Next.Visible = visibilityState
End If
If copyTarget Is positionTarget Then
CopySheetAfter.Visible = visibilityState
End If
End Function
after:=
I had left it out of my code to make it shorter, and wasn't aware of the implication (which is not really relevant actually). I've edited my question. – Fluoridate