Single Email Message bulkification is not working in Apex

First, it doesn't appear to me that you need your try-catch block at all. Instead, simply query for the users you need (not everyone in your org).

      map<Id,user>idToUser= new map([Select Id,Name,ManagerId,IsActive from user where Id IN :usrIds]);
      set<Id>mgrIds = new set();
      for (User u1 : idToUser.values()) { 
            mapUserToActive.put(u1.Id, u1.isActive);
            // you can create this map if you need it, not certain that it's necessary since you have this above in the map you queried
            mgrIds.add(u1.ManagerId);
            // collect the ids of the managers
      }

      // now query for the managers
      map<Id,user>idToManager = new map([Select Id,Name,ManagerId,IsActive from user where Id IN :mgrIds]);

      for (User u1 : idToManager.values) { 
            mapUserToActive.put(u1.Id, u1.isActive);
            // you can add them to your map if you need the map
      }

      list<user>allUsers = new list();
      // get a combined list of users and managers
      allUsers.addAll(usrs);
      allUsers.addAll(managers);          

      // query for all of the opportunities at one time
      list<Opportunity> finalOptList=new List<Opportunity>();
      map<Id,Opportunity>idToOpportunity=new map([Select Id,OwnerId,StageName from Opportunity where OwnerId in :userIds]);
      // you can optionally group this query by ownerId

      // create a map of opportunity Ids to OwnerId
      for(Opportunity opt:optys){
          if(opt.StageName!='Closed Won' && opt.StageName!='Closed Lost')
          {
              oppIdToOwnerId.put(opt.Id,opt.OwnerId);
          }

Now you should have everything you need to operate in a single for loop on user (or userID) to create your emails. You may want to create a map though of <Id,list<string>> to hold your ManagerId compared to the userIds (or names) that report to the manager. that's the only thing else I can think of that might be helpful to you. You may also want to do something similar for userId to list<OpporutnityId> or similar. I'll leave it to you to work out those details as that should be simple enough with what you have here.

EDIT:

Based on your revised code, here's what I'd recommend you do to solve your issues:

    public without sharing class ChangeOpportunityOwner {       
    @Future
    public static void changeOwner(List<Id> usrIds){
    Boolean isUpdate=false;
    List<Messaging.SingleEmailMessage> messages=new list<Messaging.SingleEmailMessage>();
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    Map<Id, Boolean> mapUserToActive = new Map<Id, Boolean>();

    map<Id,user>idToUser= new map<Id,User>([Select Id,Name,ManagerId,IsActive from user where Id IN :usrIds]);

    List<Opportunity> finalOptList=new List<Opportunity>();
    set<Id>mgrIds = new set<Id>();

    for (User u1 : idToUser.values()) { 
                mgrIds.add(u1.ManagerId);
                // collect the ids of the managers
    }

    map<Id,user>idToManager = new map<Id,User>([Select Id,Name,ManagerId,IsActive from user where Id IN :mgrIds]);

    for (User u2 : idToManager.values()) { 
        mapUserToActive.put(u2.Id, u2.isActive);
    }

    map<Id,Opportunity>idToOpportunity=new map([Select Id,OwnerId,StageName from Opportunity where OwnerId in :userIds groupBy OwnerId]);


    // create a map of opportunity Ids to OwnerId
    map<Id,Id>oppIdToOwnerId = new map<Id,Id>();

    for(Id opId:idToOpportunity.keyset()){
        if(idToOpportunity.get(opId).StageName!='Closed Won' && idToOpportunity.get(opId).StageName!='Closed Lost')
        {
            oppIdToOwnerId.put(opId,idToOpportunity.get(opId).OwnerId);
            // create map of OppIds to OwnerIds for Opps of Interest
        } 
    }

    //get list of opp Ids for each ownerId & put into map
    string OppIdStr = '';
    list<Id>UserId = new list<Id>();
    integer i = 0;
    map<Id,string>usrIdToOppIdString = new map<Id,string>();
    for(Id oId : oppIdToOwnerId.keyset()){            
        if(i=0){
            UserId[0] = oppIdToOwnerId.get(oId);
            OppIdStr = oId + ', ';
            usrIdToOppIdString.put(UserId[0],OppIdStr);
            if(mapUserToActive.get(UserId[0]
        }                 
        else if(i>0 && (oppIdToOwnerId.get(oId) == UserId[0]){
            UserId[i] = oppIdToOwnerId.get(oId).OwnerId;
            OppIdStr +=  ', '+ oId;
            usrIdToOppIdString.put(UserId[i],OppIdStr);
        }
        else{
            UserId.clear();
            i=0;
            UserId[0]=oppIdToOwnerId.get(oId);
            OppIdStr = oId + ', ';
            usrIdToOppIdString.put(UserId[0],OppIdStr);
       }
       i++;

    }


    //Run for loop on oppIdToOwnerId map         
    String UserNames = '';
    for(Id oId:oppIdToOwnerId.keyset()){   
        id managerId = idToUser.get(idToOpportunity.get(oId).OwnerId).ManagerId
        if (mapUserToActive.get(ManagerId)== true ) {
        // the above cannot be null. Would get null pointer exception 
        // when attempting to put into map if value from query was null
            idToOpportunity.get(oId).OwnerId=ManagerId;
            if(!managerIdToUserName.contains(ManagerId)){
                userNames += idToUser.get(idToOpportunity.get(oId).OwnerId).Name + ', ';
                managerIdToUserName.put(ManagerId,userNames);
            }
            else if(managerIdToUserName.contains(ManagerId) &&  !managerIdToUserName.get(ManagerId)userNames.contains(idToUser.get(idToOpportunity.get(oId).OwnerId).Name){
                userNames = managerIdToUserName.get(managerId);
                userNames += idToUser.get(idToOpportunity.get(oId).OwnerId).Name + ', ';
                managerIdToUserName.put(ManagerId,userNames);

            }

        }
        else{ 
            User usr= [Select Id,Name,ManagerId from user where Name='Test Manager'];
            idToOpportunity.get(oId).OwnerId=usr.Id;
            // are you certain this shouldn't be usr.ManagerId ?
            // this scenario seems unlikely, but you know your org best

            if(managerIdToUserName.contains(usr.Id) && !managerIdToUserName.get(usr.Id).contains(idToUser.get(idToOpportunity.get(oId).OwnerId).Name){
                userNames = managerIdToUserName.get(usr.Id);
                userNames += idToUser.get(idToOpportunity .get(oId).OwnerId).Name + ', ';
                managerIdToUserName.put(usrId,userNames);


            }
            else if(!managerIdToUserName.contains(usr.Id)){
                userNames = idToUser.get(idToOpportunity.get(oId).OwnerId).Name + ', ';
                managerIdToUserName.put(usrId,userNames);
            }
        }

    finalOptList.add(idToOpportunity.get(oId));
    }

    // Now create the emails using the maps in a for loop either on ManagerId 
    // or on Opportunity Id if you want them combined into one per manager

Will leave the rest to you.

AVOID ITERATING ON MAP VALUES as you were on this line: for(User u: idToUser.values()){.

I do not recommend using nested SOQL queries as you do in your current code. Instead, take them outside as I've shown above in both examples to create your maps.

These are deeply nested maps and you must keep them straight which I know can be difficult to do. There are probably cleaner ways to do some of this, but I don't have time to write all of your code for you. Use this as a basis for finishing writing your code. All you need do now is finish the loop for your email.