0

У меня есть ViewPager с двумя вкладками в первом, это список мест, а второй я хочу быть картой мест. Теперь я могу заполнить список из базы данных, и у меня есть карта, работающая в другом месте приложения, но у меня возникают проблемы с ее работой с макетом вкладки в виде фрагмента.Каков наилучший способ использования MapFragment в ViewPager?

Вот код для моего фрагмента карты:

import java.util.ArrayList; 

import android.annotation.SuppressLint; 
import android.content.Intent; 
import android.database.Cursor; 
import android.net.Uri; 
import android.os.Build; 
import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.LoaderManager; 
import android.support.v4.content.CursorLoader; 
import android.support.v4.content.Loader; 
import android.util.Log; 
import android.view.View; 
import android.view.ViewTreeObserver.OnGlobalLayoutListener; 

import com.google.android.gms.maps.CameraUpdateFactory; 
import com.google.android.gms.maps.GoogleMap; 
import com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener; 
import com.google.android.gms.maps.model.LatLng; 
import com.google.android.gms.maps.model.LatLngBounds; 
import com.google.android.gms.maps.model.Marker; 
import com.google.android.gms.maps.model.MarkerOptions; 

public class MapFragment extends Fragment implements OnInfoWindowClickListener, 
     LoaderManager.LoaderCallbacks<Cursor> { 

    MarkerOptions options = new MarkerOptions(); 
    LatLngBounds.Builder build = new LatLngBounds.Builder(); 
    GoogleMap map; 

    double[] lats; 
    double[] lngs; 
    String[] names; 
    String[] types; 
    int count; 
    int[] ids; 

    // @Override 
    // public View onCreateView(LayoutInflater inflater, ViewGroup container, 
    // Bundle savedInstanceState) { 
    // View v = (RelativeLayout) inflater.inflate(R.layout.dialog_map, 
    // container, false); 
    // setUpMapIfNeeded(null, null); 
    // setupMarkers(); 
    // LatLngBounds bounds = build.build(); 
    // setUpMapIfNeeded(null, bounds); 
    // return v; 
    // } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
     // setContentView(R.layout.dialog_map); 

     // setUpMapIfNeeded(null, null); 

     // Prepare the loader. Either re-connect with an existing one, 
     // or start a new one. 
     getLoaderManager().initLoader(0, null, this); 
    } 

    private void setupMarkers() { 
     // get the passed crags names and locations 
     // double[] lats = getArguments().getDoubleArray(ClimbProvider.LAT); 
     // double[] lngs = getArguments().getDoubleArray(ClimbProvider.LONG); 
     // ArrayList<String> names = getArguments().getStringArrayList(
     // ClimbProvider.NAME); 
     // interate and add every passed crag to the map as a marker 
     for (int i = 0; i < count; i++) { 
      // add the crags name and location to the marker 
      LatLng pos = new LatLng(lats[i], lngs[i]); 
      options.position(pos); 
      options.title((String) names[i]); 
      // add the marker to the map 
      map.addMarker(options); 
      map.setOnInfoWindowClickListener(this); 
      build.include(pos); 
     } 
    } 

    private void setUpMapIfNeeded(MarkerOptions options, 
      final LatLngBounds bounds) { 
     if (options == null && bounds == null) { 
      map = ((MapFragment) getFragmentManager().findFragmentById(
        R.id.map)).getMap(); 
     } else if (bounds != null) { 
      map.setMapType(GoogleMap.MAP_TYPE_HYBRID); 
      map.getUiSettings().setZoomControlsEnabled(false); 
      try { 
       map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 70)); 
      } catch (IllegalStateException e) { 
       // layout not yet initialised 
       final View mapView = getFragmentManager().findFragmentById(
         R.id.map).getView(); 
       if (mapView.getViewTreeObserver().isAlive()) { 
        mapView.getViewTreeObserver().addOnGlobalLayoutListener(
          new OnGlobalLayoutListener() { 

           @SuppressWarnings("deprecation") 
           @SuppressLint("NewApi") 
           // We check which build version we are using. 
           @Override 
           public void onGlobalLayout() { 
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 
             mapView.getViewTreeObserver() 
               .removeGlobalOnLayoutListener(
                 this); 
            } else { 
             mapView.getViewTreeObserver() 
               .removeOnGlobalLayoutListener(
                 this); 
            } 
            map.moveCamera(CameraUpdateFactory 
              .newLatLngBounds(bounds, 70)); 
           } 
          }); 
       } 

      } 
     } 
    } 

    // when an info bubble is clicked get its title and search for it in the 
    // list of crag names the cross reference this with the list of crag ids and 
    // pass that to the view crag activity 
    @Override 
    public void onInfoWindowClick(Marker marker) { 
     int id = -1; 
     for (int i = 0; i < count; i++) { 
      if (names[i].contentEquals(marker.getTitle())) { 
       id = ids[i]; 
      } 
     } 
     Intent viewCrag = new Intent(getActivity(), CragViewActivity.class); 
     viewCrag.putExtra("id", id); 
     Log.d("ClimbTrack", "row id = " + id); 
     startActivity(viewCrag); 
    } 

    @Override 
    public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
     // This is called when a new Loader needs to be created. This 
     // sample only has one Loader, so we don't care about the ID. 
     // First, pick the base URI to use depending on whether we are 
     // currently filtering. 
     Uri allcrags = Uri 
       .parse("content://com.fooforever.climbtrack.provider/crags"); 
     return new CursorLoader(getActivity(), allcrags, null, null, null, null); 
    } 

    @Override 
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
     ArrayList<Double> latsArray = new ArrayList<Double>(); 
     ArrayList<Double> lngsArray = new ArrayList<Double>(); 
     ArrayList<Integer> idsArray = new ArrayList<Integer>(); 
     ArrayList<String> namesArray = new ArrayList<String>(); 
     ArrayList<String> typesArray = new ArrayList<String>(); 
     // Swap the new cursor in. (The framework will take care of closing the 
     // old cursor once we return.) 
     // mAdapter.swapCursor(data); 
     // move to the top of the query results 
     data.moveToFirst(); 
     // put all the ids from the result into a list so they can be 
     // referenced against the listview item id 
     while (data.isAfterLast() == false) { 
      idsArray.add(data.getInt(data.getColumnIndex(ClimbProvider._ID))); 
      latsArray 
        .add(data.getDouble(data.getColumnIndex(ClimbProvider.LAT))); 
      lngsArray.add(data.getDouble(data 
        .getColumnIndex(ClimbProvider.LONG))); 
      namesArray.add(data.getString(data 
        .getColumnIndex(ClimbProvider.NAME))); 
      typesArray.add(data.getString(data 
        .getColumnIndex(ClimbProvider.TYPE))); 
      data.moveToNext(); 
     } 

     count = data.getCount(); 
     lats = new double[count]; 
     lngs = new double[count]; 
     names = new String[count]; 
     types = new String[count]; 
     ids = new int[count]; 
     convert_arr_double(latsArray, lats); 
     convert_arr_double(lngsArray, lngs); 
     convert_arr_string(namesArray, names); 
     convert_arr_string(typesArray, types); 
     convert_arr_int(idsArray, ids); 

     // The list should now be shown. 
     // if (isResumed()) { 
     // setListShown(true); 
     // } else { 
     // setListShownNoAnimation(true); 
     // } 
     setupMarkers(); 
     LatLngBounds bounds = build.build(); 
     setUpMapIfNeeded(null, bounds); 

    } 

    @Override 
    public void onLoaderReset(Loader<Cursor> arg0) { 
     // TODO 
    } 

    // convert the passed arraylist to a double array 
    private void convert_arr_double(ArrayList<Double> array, double[] out) { 
     for (int i = 0; i < count; i++) { 
      out[i] = array.get(i); 
     } 
    } 

    private void convert_arr_string(ArrayList<String> array, String[] out) { 
     for (int i = 0; i < count; i++) { 
      out[i] = array.get(i); 
     } 
    } 

    private void convert_arr_int(ArrayList<Integer> array, int[] out) { 
     for (int i = 0; i < count; i++) { 
      out[i] = array.get(i); 
     } 
    } 
} 

Я получаю ошибку компиляции на инициализации карты в функции setupmapifneeded().

on line 88 4/5-я строка функции setupmap ifneeded().

Я не могу понять, почему я получаю ошибку компиляции здесь, и это лучший способ реализовать эту функцию?

ответ

2

Использование ViewPager для перемещения между списком и картой может привести к некоторым неприятным поведением - попытка панорамирования карты может привести к переключению просмотров или наоборот.

Вы можете использовать обычную навигацию (которая удаляет любую фоновую перестановку панорамирования/просмотра), или вы можете реализовать кнопку блокировки для просмотра карты, чтобы заблокировать панорамирование.

Относительно того, почему вы получаете ошибку компиляции:

public class MapFragment extends Fragment implements OnInfoWindowClickListener, 
    LoaderManager.LoaderCallbacks<Cursor> { 
    ... 
    map = ((MapFragment) getFragmentManager().findFragmentById(
       R.id.map)).getMap(); 
} 

Вы кастинг на неправильный тип MapFragment. Либо переименовать вашMapFragment (скажем, AppNameMapFragment) или полностью уточнят бросок:

Вы были ранее попытки бросить из Fragmentв вашейMapFragment. В моем предыдущем ответе я пропустил, что вы также пользуетесь библиотекой поддержки. Таким образом, вы должны использовать getSupportFragmentManager, и вы должны бросить в SupportMapFragment:

map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(
       R.id.map)).getMap(); 
+1

«пытаются прокручивать карту может привести к переключению вид, или наоборот» - подкласс 'ViewPager', переопределение' canScroll() 'и укажите, что события касания на карте должны перейти на карту. Вот пример приложения, демонстрирующий это: https://github.com/commonsguy/cw-omnibus/tree/master/MapsV2/Pager – CommonsWare

+0

Это эффективно для страниц, на которых вы можете коснуться где-то за пределами карты, чтобы инициировать изменение на другую страницу ; со страницами, где весь вид представляет собой карту, это создает непоследовательное поведение, не так ли? Проведите по экрану, чтобы изменить страницу в списке, но нажмите индикатор страницы вверху, чтобы изменить страницу, когда на карте? –

+1

"со страницами, где весь вид представляет собой карту, это создает непоследовательное поведение, не так ли?" - правильно, и мой пример несколько демонстрирует это, так как единственный способ изменить страницы - это вкладки. Тем не менее, «ViewPager» по-прежнему является более гибким, чем многие альтернативы (например, «FragmentTabHost») для реализации вкладок. Без вкладок или эквивалента карта, занимающая всю страницу, делает «ViewPager» бессмысленной, так что это ошибка дизайна пользовательского интерфейса. Я не являюсь поклонником дизайна пользовательского интерфейса OP (список на одной странице, карта в другом), поскольку IMHO - это неправильное использование «ViewPager» и горизонтального прокрутки. – CommonsWare

Смежные вопросы