Android Ein dynamisches Widget in Form von Karten basierend auf StackView (so etwas wie Tinder)

UPD: Das Widget ist nicht mehr fehlerhaft, alles ist behoben

Hallo an alle.

Vor einem Monat wurde ein Artikel über meinen ersten Antrag auf Bilanzierung persönlicher und familiärer Finanzen veröffentlicht.

Seitdem habe ich den Namen in "Budget & Warenkorb" geändert und dementsprechend Funktionen hinzugefügt, mit denen Sie schnell einen Warenkorb erstellen und verwenden können.

Warenkorb-Widget



Der Mechanismus zum Erstellen eines Einkaufswagens ist recht einfach, logisch und daher praktisch:
Im Verzeichnisbaum

Sie markieren mehrere Artikel innerhalb der Kategorie und klicken auf die Schaltfläche "In den Warenkorb". Diese Liste der Positionen mit der Stammkategorie wird als Widgetkarte angezeigt. Diese Aktion kann beliebig oft wiederholt werden.

Aus diesem Grund haben wir Einkaufslisten logisch gruppiert.
Das Schöne ist, dass es sofort in allen Mitgliedern der Gruppe erscheint, d.h. Mama schuf Karten und Papa fuhr den Weg entlang und kaufte alles.
Klicken Sie auf die Karte und das Formular zur Eingabe des Betrags wird geöffnet. Geben Sie daher den Betrag nicht für jeden Artikel, sondern für die übergeordnete Kategorie als Ganzes ein. Das heißt, Die Idee ist, dass wir die detaillierten Kategorien für den Kaufplan verwenden und der Betrag von der übergeordneten Kategorie gröber berücksichtigt wird.


Implementierung

1. Serviceklasse
public class StackWidgetService extends RemoteViewsService { @Override public void onCreate() { super.onCreate(); } @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new StackRemoteViewsFactory(this.getApplicationContext(), intent); } } 


2. Adapterklasse für Kartenstapel
 public class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { private List<MoneyTransaction> mWidgetItems = new ArrayList<MoneyTransaction>(); private Context mContext; @Inject FirestoreRepository repository; public StackRemoteViewsFactory(Context context, Intent intent) { mContext = context; Injector.getApplicationComponent().inject(this); } public void onCreate() { } public void onDestroy() { // repository.getLiveOrders().removeObserver(observer); // In onDestroy() you should tear down anything that was setup for your data source, // eg. cursors, connections, etc. mWidgetItems.clear(); } public int getCount() { return mWidgetItems.size(); } public RemoteViews getViewAt(int position) { // position will always range from 0 to getCount() - 1. // We construct a remote views item based on our widget item xml file, and set the // text based on the position. RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_stack_orders_item); if(position < mWidgetItems.size()) { MoneyTransaction moneyTransaction = mWidgetItems.get(position); String dateStr = FormatTool.getDateStringShort(moneyTransaction.getDate()); rv.setTextViewText(R.id.tv_date, dateStr); rv.setTextViewText(R.id.tv_correspondent, moneyTransaction.getCategoryObject().getName()); rv.setTextViewText(R.id.tv_comment, moneyTransaction.getComment()); Date today = FormatTool.getStartOfPeriod(Calendar.getInstance().getTime(), Constants.PERIODICITY_DAY); Date date = FormatTool.getStartOfPeriod(moneyTransaction.getDate(), Constants.PERIODICITY_DAY); long days = TimeUnit.MILLISECONDS.toDays(today.getTime() - date.getTime()); if(days < 0) { rv.setInt(R.id.widget_item, "setBackgroundResource", R.drawable.blue_with_border); } else if(days == 0) { rv.setInt(R.id.widget_item, "setBackgroundResource", R.drawable.green_with_border); } else if(days == 1) { rv.setInt(R.id.widget_item, "setBackgroundResource", R.drawable.orange_with_border); } else { rv.setInt(R.id.widget_item, "setBackgroundResource", R.drawable.red_with_border); } // Next, we set a fill-intent which will be used to fill-in the pending intent template // which is set on the collection view in StackWidgetProvider. Bundle extras = new Bundle(); extras.putString(FirestoreTables.PATH, moneyTransaction.getPath()); Intent fillInIntent = new Intent(); fillInIntent.setAction(OrdersWidgetProvider.CLICK_ACTION); fillInIntent.putExtras(extras); rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent); } // Return the remote views object. return rv; } public RemoteViews getLoadingView() { // You can create a custom loading view (for instance when getViewAt() is slow.) If you // return null here, you will get the default loading view. return null; } public int getViewTypeCount() { return 1; } public long getItemId(int position) { return position; } public boolean hasStableIds() { return true; } public void onDataSetChanged() { mWidgetItems = repository.getOrdersSync(); } } 


3. Widget-Provider-Klasse
        .       -  2 : -             ( onDataSetChanged     ) -        -        . public class OrdersWidgetProvider extends AppWidgetProvider { public static final String CLICK_ACTION = "click_action"; private Observer observer; @Inject FirestoreRepository repository; public OrdersWidgetProvider() { super(); Injector.getApplicationComponent().inject(this); } @Override public void onReceive(Context context, Intent intent) { if(CLICK_ACTION.equals(intent.getAction())) { String path = intent.getStringExtra(FirestoreTables.PATH); repository.getTransaction(path) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(transaction -> { if(transaction != null) { Intent launchIntent = new Intent(context, TransactionDetailActivity.class); launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); launchIntent.putExtra(Constants.TRANSACTION, transaction); context.startActivity(launchIntent); } }); } super.onReceive(context, intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { LiveData<List<MoneyTransaction>> liveData = repository.getLiveOrders(); if(observer != null && liveData.hasActiveObservers()) { liveData.removeObserver(observer); } observer = (Observer<List<MoneyTransaction>>) moneyTransactions -> { repository.setOrders(moneyTransactions); appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.stack_view); }; liveData.observeForever(observer); // update each of the widgets with the remote adapter for (int i = 0; i < appWidgetIds.length; ++i) { // Here we setup the intent which points to the StackViewService which will // // provide the views for this collection. Intent intent = new Intent(context, StackWidgetService.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); // // When intents are compared, the extras are ignored, so we need to embed the extras // // into the data so that the extras will not be ignored. intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_stack_orders_layout); rv.setRemoteAdapter(R.id.stack_view, intent); // // // The empty view is displayed when the collection has no items. It should be a sibling // // of the collection view. rv.setEmptyView(R.id.stack_view, R.id.empty_view); // // Here we setup the a pending intent template. Individuals items of a collection // // cannot setup their own pending intents, instead, the collection as a whole can // // setup a pending intent template, and the individual items can set a fillInIntent // // to create unique before on an item to item basis. Intent intent1 = new Intent(context, OrdersWidgetProvider.class); intent1.setAction(CLICK_ACTION); intent1.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT); rv.setPendingIntentTemplate(R.id.stack_view, pendingIntent); appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds[i], R.id.stack_view); appWidgetManager.updateAppWidget(appWidgetIds[i], rv); } super.onUpdate(context, appWidgetManager, appWidgetIds); } @Override public void onDisabled(Context context) { super.onDisabled(context); repository.getLiveOrders().removeObserver(observer); } } 


4. Widget-Layout
 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <StackView android:id="@+id/stack_view" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:loopViews="true"/> <LinearLayout android:id="@+id/empty_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/round_light_button_switcher" android:orientation="vertical"> <ImageView android:layout_width="wrap_content" android:layout_height="200dp" android:layout_margin="2dp" android:src="@drawable/beans_horizontal"/> <TextView style="@style/PrimaryDarkBold26" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginLeft="20dp" android:layout_marginTop="-40dp" android:layout_marginRight="20dp" android:layout_marginBottom="20dp" android:gravity="bottom|center_horizontal" android:text="@string/empty_view_text" android:textStyle="bold"/> </LinearLayout> </FrameLayout> 


5. Kartenaufschlag
 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/widget_item" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tv_correspondent" style="@style/White20" android:layout_width="match_parent" android:layout_height="50dp" android:ellipsize="end" /> <LinearLayout style="@style/WhiteDividerStyle" android:layout_marginTop="4dp"/> <TextView android:id="@+id/tv_comment" style="@style/White18" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="4dp" android:ellipsize="end" android:maxLines="20"/> <LinearLayout style="@style/WhiteDividerStyle"/> <TextView android:id="@+id/tv_date" style="@style/White18" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="4dp"/> </LinearLayout> 


6. Beschreibung des XML-Anbieters
 <?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/widget_stack_orders_layout" android:minWidth="150dp" android:minHeight="200dp" android:previewImage="@drawable/widget"> </appwidget-provider> 

Source: https://habr.com/ru/post/de452998/


All Articles