24

Kart Görünümlerini görüntüleyen bir GridLayoutManager ile bir RecyclerView var. Kartların ekran boyutuna göre yeniden düzenlenmesini istiyorum (Google Play uygulaması uygulama kartları ile bu tür bir şeyi yapıyor). İşte bir örnek:GridLayoutManager - sütunları otomatik olarak nasıl sığdırabilirim?

enter image description here

enter image description here İşte

benim app şu anda böyle görünüyor:

enter image description here

enter image description here

kartları sadece görebileceğiniz gibi germek ve orienta yapılan boş alana uymuyor tion değişimi. Peki bunu nasıl yapabilirim?

Kodu:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Json; 
using System.Threading; 
using System.Threading.Tasks; 
using Android.Media; 
using Android.App; 
using Android.Support.V4.App; 
using Android.Support.V4.Content.Res; 
using Android.Support.V4.Widget; 
using Android.Support.V7.Widget; 
using Android.Content; 
using Android.OS; 
using Android.Runtime; 
using Android.Util; 
using Android.Views; 
using Android.Widget; 
using Android.Net; 
using Android.Views.Animations; 
using Android.Graphics; 
using Android.Graphics.Drawables; 
using Newtonsoft.Json; 
using *******.Adapters; 
using *******.Models; 

namespace *******.Fragments { 
    public class Dashboard : GridLayoutBase { 
     private ISharedPreferences pref; 
     private SessionManager session; 
     private string cookie; 
     private DeviceModel deviceModel; 
     private RecyclerView recyclerView; 
     private RecyclerView.Adapter adapter; 
//  private RecyclerView.LayoutManager layoutManager; 
     private GridLayoutManager gridLayoutManager; 
     private List<ItemData> itemData; 
     private Bitmap lastPhotoBitmap; 
     private Drawable lastPhotoDrawable; 
     private static Activity activity; 
     private ProgressDialog progressDialog; 
     private TextView noData; 
     private const string URL_DASHBOARD = "http://192.168.1.101/appapi/getdashboard"; 
     private const string URL_DATA = "http://192.168.1.101/appapi/getdata"; 

     public override void OnCreate(Bundle bundle) { 
      base.OnCreate(bundle); 

      activity = Activity; 
      session = new SessionManager(); 
      pref = activity.GetSharedPreferences("UserSession", FileCreationMode.Private); 
      cookie = pref.GetString("PHPSESSID", string.Empty); 
     } 

     public async override void OnStart() { 
      base.OnStart(); 

      progressDialog = ProgressDialog.Show(activity, String.Empty, GetString(Resource.String.loading_text)); 
      progressDialog.Window.ClearFlags(WindowManagerFlags.DimBehind); 

      await GetDevicesInfo(); 

      if (deviceModel.Error == "true" && deviceModel.ErrorType == "noSensors") { 
       recyclerView.Visibility = ViewStates.Gone; 
       noData.Visibility = ViewStates.Visible; 

       progressDialog.Hide(); 

       return; 
      } else { 
       recyclerView.Visibility = ViewStates.Visible; 
       noData.Visibility = ViewStates.Gone; 

       await PopulateSensorStates(); 
      } 

//   DisplayLastPhoto(); 

      adapter = new ViewAdapter(itemData); 

      new System.Threading.Thread(new System.Threading.ThreadStart(() => { 
       activity.RunOnUiThread(() => { 
        recyclerView.SetAdapter(adapter); 
       }); 
      })).Start(); 

      progressDialog.Hide(); 
     } 

     public async Task GetDevicesInfo() { 
      var jsonFetcher = new JsonFetcher(); 
      JsonValue jsonDashboard = await jsonFetcher.FetchDataWithCookieAsync(URL_DASHBOARD, cookie); 
      deviceModel = new DeviceModel(); 
      deviceModel = JsonConvert.DeserializeObject<DeviceModel>(jsonDashboard); 
     } 

     // Shows sensor states 
     public async Task PopulateSensorStates() { 
      itemData = new List<ItemData>(); 
      string lastValue = String.Empty; 

      foreach (var sensor in this.deviceModel.Sensors) { 
       var sensorImage = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.smoke_red, null); 

       switch (sensor.Type) { 
       case "2": 
        var jsonFetcher = new JsonFetcher(); 
        JsonValue jsonData = await jsonFetcher.FetchSensorDataAsync(URL_DATA, sensor.Id, "DESC", "1", cookie); 
        var deviceModel = new DeviceModel(); 
        deviceModel = JsonConvert.DeserializeObject<DeviceModel>(jsonData); 
        lastValue = deviceModel.SensorData.Last().Value; 
        break; 
       case "4": 
        await RenderLastCameraPhoto(); 
        sensorImage = new BitmapDrawable(Resources, lastPhotoBitmap); 
        break; 
       } 

       itemData.Add(new ItemData() { 
        id = sensor.Id, 
        value = lastValue, 
        type = sensor.Type, 
        image = sensorImage, 
        title = sensor.Name.First().ToString().ToUpper() + sensor.Name.Substring(1).ToLower(), 
       }); 
      } 
     } 

     // Shows the last camera photo 
     public async Task RenderLastCameraPhoto() { 
      if (deviceModel.Error == "true" && deviceModel.ErrorType == "noPhoto") { 
       //TODO: Show a "No photo" picture 
      } else { 
       string url = deviceModel.LastPhotoLink; 
       lastPhotoBitmap = await new ImageDownloader().GetImageBitmapFromUrlAsync(url, activity, 300, 300); 
      } 
     } 

     public async void UpdateData(bool isSwipeRefresh) { 
      await GetDevicesInfo(); 

      if (deviceModel.Error == "true" && deviceModel.ErrorType == "noSensors") { 
       recyclerView.Visibility = ViewStates.Gone; 
       noData.Visibility = ViewStates.Visible; 

       return; 
       } else { 
       recyclerView.Visibility = ViewStates.Visible; 
       noData.Visibility = ViewStates.Gone; 

       await PopulateSensorStates(); 
      } 

      adapter = new ViewAdapter(itemData); 

      new System.Threading.Thread(new System.Threading.ThreadStart(() => { 
       activity.RunOnUiThread(() => { 
        recyclerView.SetAdapter(adapter); 
       }); 
      })).Start(); 

      adapter.NotifyDataSetChanged(); 
     } 

     public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
      View view = inflater.Inflate(Resource.Layout.Dashboard, container, false); 
      noData = view.FindViewById<TextView>(Resource.Id.no_data_title); 

      SwipeRefreshLayout swipeRefreshLayout = view.FindViewById<SwipeRefreshLayout>(Resource.Id.swipe_container); 
      //   swipeRefreshLayout.SetColorSchemeResources(Color.LightBlue, Color.LightGreen, Color.Orange, Color.Red); 

      // On refresh button press/swipe, updates the recycler view with new data 
      swipeRefreshLayout.Refresh += (sender, e) => { 
       UpdateData(true); 

       swipeRefreshLayout.Refreshing = false; 
      }; 

      var gridLayoutManager = new GridLayoutManager(activity, 2); 

      recyclerView = view.FindViewById<RecyclerView>(Resource.Id.dashboard_recycler_view); 
      recyclerView.HasFixedSize = true; 
      recyclerView.SetLayoutManager(gridLayoutManager); 
      recyclerView.SetItemAnimator(new DefaultItemAnimator()); 
      recyclerView.AddItemDecoration(new SpaceItemDecoration(15)); 

      return view; 
     } 

     public class ViewAdapter : RecyclerView.Adapter { 
      private List<ItemData> itemData; 
      public string sensorId; 
      public string sensorType; 
      private ImageView imageId; 
      private TextView sensorValue; 
      private TextView sensorTitle; 

      public ViewAdapter(List<ItemData> itemData) { 
       this.itemData = itemData; 
      } 

      public class ItemView : RecyclerView.ViewHolder { 
       public View mainView { get; set; } 

       public string id { get; set; } 

       public string type { get; set; } 

       public ImageView image { get; set; } 

       //    public TextView value { get; set; } 

       public TextView title { get; set; } 

       public ItemView(View view) : base(view) { 
        mainView = view; 
       } 
      } 

      public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) { 
       View itemLayoutView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.DashboardItems, null); 
       CardView cardView = itemLayoutView.FindViewById<CardView>(Resource.Id.dashboard_card_view); 
       imageId = itemLayoutView.FindViewById<ImageView>(Resource.Id.sensor_image); 
//    sensorValue = itemLayoutView.FindViewById<TextView>(Resource.Id.sensor_value); 
       sensorTitle = itemLayoutView.FindViewById<TextView>(Resource.Id.sensor_title); 

       var viewHolder = new ItemView(itemLayoutView) { 
        id = sensorId, 
        type = sensorType, 
        image = imageId, 
//     value = sensorValue, 
        title = sensorTitle 
       }; 

       return viewHolder; 
      } 

      public override void OnBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { 
       ItemView itemHolder = viewHolder as ItemView; 

       itemHolder.image.SetImageDrawable(itemData[position].image); 

       if (itemData[position].type == "2") { // Temperature 
        itemHolder.title.Text = itemData[position].title + ": " + itemData[position].value; 
       } else { 
        itemHolder.title.Text = itemData[position].title; 
       } 

       var bundle = new Bundle(); 
       var dualColumnList = new DualColumnList(); 
       var gallery = new Gallery(); 

       EventHandler clickUpdateViewEvent = ((sender, e) => { 
        bundle.PutString("id", itemData[position].id); 
        gallery.Arguments = bundle; 
        dualColumnList.Arguments = bundle; 

        if (itemData[position].type == "4") { // Camera 
         ((FragmentActivity)activity).ShowFragment(gallery, itemData[position].title, itemData[position].type, true); 
        } else { 
         ((FragmentActivity)activity).ShowFragment(dualColumnList, itemData[position].title, itemData[position].type, true); 
        } 
       }); 

       itemHolder.image.Click += clickUpdateViewEvent; 
//    itemHolder.value.Click += clickUpdateViewEvent; 
       itemHolder.title.Click += clickUpdateViewEvent; 
      } 

      public override int ItemCount { 
       get { return itemData.Count; } 
      } 
     } 

     public class ItemData { 
      public string id { get; set; } 

      public string type { get; set; } 

      public Drawable image { get; set; } 

      public string value { get; set; } 

      public string title { get; set; } 
     } 
    } 
} 

Fragment Düzen:

<?xml version="1.0" encoding="utf-8"?> 
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/swipe_container" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 
    <LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:gravity="center_horizontal" 
     android:weightSum="1"> 
     <RelativeLayout 
      android:layout_width="0dp" 
      android:layout_height="match_parent" 
      android:layout_weight="0.9" 
      android:scrollbars="vertical"> 
      <android.support.v7.widget.RecyclerView 
       android:id="@+id/dashboard_recycler_view" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" /> 
      <TextView 
       android:text="@string/no_data_text" 
       android:id="@+id/no_data_title" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:textSize="30sp" 
       android:gravity="center" 
       android:layout_centerInParent="true" /> 
     </RelativeLayout> 
    </LinearLayout> 
</android.support.v4.widget.SwipeRefreshLayout> 

Fragment Öğeler Düzen:

<?xml version="1.0" encoding="utf-8"?> 
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/dashboard_card_view" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"> 
    <LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:gravity="center_horizontal" 
     android:orientation="vertical" 
     android:foreground="?android:attr/selectableItemBackground"> 
     <ImageView 
      android:id="@+id/sensor_image" 
      android:layout_width="120dp" 
      android:layout_height="120dp" 
      android:paddingTop="5dp" 
      android:layout_alignParentTop="true" /> 
    <!--  <TextView 
      android:id="@+id/sensor_value" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:textSize="30sp" 
      android:layout_below="@id/sensor_image" 
      android:gravity="center" />--> 
     <TextView 
      android:id="@+id/sensor_title" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:textSize="23sp" 
      android:layout_below="@id/sensor_image" 
      android:gravity="center" 
      android:layout_alignParentBottom="true" /> 
    </LinearLayout> 
</android.support.v7.widget.CardView> 
+0

Hey çözüm buldunuz mu? Ben de, –

+0

sıkışmış Ben, ben geri dönüştürmek için gerçek genişlik verdiğinizde, onun öğeleri autofit. –

cevap

49

Sütun sayısını hesaplayabilir ve görüntüyü hesaplanan şekilde yükleyebilirsiniz. olarak hesaplamak için statik bir funtion tanımlayın:

public class Utility { 
    public static int calculateNoOfColumns(Context context) { 
     DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); 
     float dpWidth = displayMetrics.widthPixels/displayMetrics.density; 
     int noOfColumns = (int) (dpWidth/180); 
     return noOfColumns; 
    } 
} 

Sonra aktivite veya fragmanında onu kullanırken böyle yapabilirsiniz:

int mNoOfColumns = Utility.calculateNoOfColumns(getApplicationContext()); 

............ 
mGridLayoutManager = new GridLayoutManager(this, mNoOfColumns); 
+0

Müthiş Kod. Benim için mükemmel çalışıyor. 180'i 140 ile değiştirdiğimde. – Abhishek

+0

Cevapta '180' nedir? – khateeb

+2

180, ızgara öğenizin genişliğidir. Sözleşmenize göre değiştirebilirsiniz. – Ariq

1

Oluşturucu new GridLayoutManager(activity, 2) yaklaşık GridLayoutManager(Context context, int spanCount)spanCount ızgara sütun sayısıdır olduğunu.

Bu genişlikte pencere/görünüm genişliğini ve tabanını kontrol etmenin en iyi yolu, kaç tane kapağın göstermek istediğinizi saymaktır.

17

GridLayoutManager en constructor

Bir integer resource değeri ile yöneticisi başlatmak ve different screens için farklı değerler sağlayabilir

ızgara sütun sayısı olan bir bağımsız değişken spanCount sahiptir (diğer bir deyişle values-w600 , values-large, values-land).

3

Ben @Riten cevabını çalıştı ve FUNTASTIC çalıştı !! Ama "180" Yani bu şekilde modifiye kodlanmış memnun değildi:

public class ColumnQty { 
    private int width, height, remaining; 
    private DisplayMetrics displayMetrics; 

    public ColumnQty(Context context, int viewId) { 

     View view = View.inflate(context, viewId, null); 
     view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); 
     width = view.getMeasuredWidth(); 
     height = view.getMeasuredHeight(); 
     displayMetrics = context.getResources().getDisplayMetrics(); 
    } 
    public int calculateNoOfColumns() { 

     int numberOfColumns = displayMetrics.widthPixels/width; 
     remaining = displayMetrics.widthPixels - (numberOfColumns * width); 
//  System.out.println("\nRemaining\t" + remaining + "\nNumber Of Columns\t" + numberOfColumns); 
     if (remaining/(2 * numberOfColumns) < 15) { 
      numberOfColumns--; 
      remaining = displayMetrics.widthPixels - (numberOfColumns * width); 
     } 
     return numberOfColumns; 
    } 
    public int calculateSpacing() { 

     int numberOfColumns = calculateNoOfColumns(); 
//  System.out.println("\nNumber Of Columns\t"+ numberOfColumns+"\nRemaining Space\t"+remaining+"\nSpacing\t"+remaining/(2*numberOfColumns)+"\nWidth\t"+width+"\nHeight\t"+height+"\nDisplay DPI\t"+displayMetrics.densityDpi+"\nDisplay Metrics Width\t"+displayMetrics.widthPixels); 
     return remaining/(2 * numberOfColumns); 
    } 
} 

Nerede "viewId" yılında R.layout.item_for_recycler gibi RecyclerView görünümler olarak kullanılacak düzenidir

Sadece Genişlik almak için kullandığımdan View.inflate'un etkisi hakkında emin değilim.

sonra GridLayoutManager I yapın:

GridLayoutManager gridLayoutManager = new GridLayoutManager(this, Utility.columnQty(this, R.layout.item_for_recycler)); 

UPDATE: I kılavuz içinde minimum genişlikte aralık almak için kullanmak gibi kodunda daha hatları ilave edildi. Hesaplama aralığı:

recyclerPatternsView.addItemDecoration(new GridSpacing(columnQty.calculateSpacing())); 
+0

Merhaba Racu, size yöntem denedim, ancak 'view.getMeasuredWidth() 'her zaman 0 döndürür. Herhangi bir fikir mi? – Sam

+0

Hiçbir fikrim yok, sadece belki xml olduğunu düşünebilirsin, "0dp" ye sahip olabilirsin. Bazı değişiklikleri yaptığım için tüm sınıfı güncelleyeceğim. – Racu

+0

@Sam En son sürümüne güncelledim, öğeler arasındaki mesafeyi ayarlamak için kullanıyorum. Burada "15", alan bahislerinin en az 15 piksel olacağını garanti eder, eğer daha az ise, yöntem bir sütunu kaldırır ve boşlukları yeniden hesaplar. Dilek "15px" "15dp" veya daha az kodlanmış bir şey yapabilirdim. GL – Racu