рдПрдВрдбреНрд░реЙрдпрдбред StackView рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдХрд╛рд░реНрдб рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рдЧрддрд┐рд╢реАрд▓ рд╡рд┐рдЬреЗрдЯ (рдЯрд┐рдВрдбрд░ рдХреА рддрд░рд╣ рдХреБрдЫ)

UPD: рд╡рд┐рдЬреЗрдЯ рдЕрдм рдЫреЛрдЯреА рдирд╣реАрдВ рд╣реИ, рд╕рдм рдХреБрдЫ рддрдп рд╣реЛ рдЧрдпрд╛ рд╣реИ

рд╕рднреА рдХреЛ рдирдорд╕реНрдХрд╛рд░ред

рдПрдХ рдорд╣реАрдиреЗ рдкрд╣рд▓реЗ, рд╡реНрдпрдХреНрддрд┐рдЧрдд рдФрд░ рдкрд╛рд░рд┐рд╡рд╛рд░рд┐рдХ рд╡рд┐рддреНрдд рдХреЗ рд▓рд┐рдП рд▓реЗрдЦрд╛рдВрдХрди рдХреЗ рд▓рд┐рдП рдореЗрд░реЗ рдкрд╣рд▓реЗ рдЖрд╡реЗрджрди рдкрд░ рдПрдХ рд▓реЗрдЦ рдкреНрд░рдХрд╛рд╢рд┐рдд рд╣реБрдЖ рдерд╛ред

рддрдм рд╕реЗ, рдореИрдВрдиреЗ рдирд╛рдо рдХреЛ "рдмрдЬрдЯ рдФрд░ рдЦрд░реАрджрд╛рд░реА рдХреА рдЯреЛрдХрд░реА" рдореЗрдВ рдмрджрд▓ рджрд┐рдпрд╛ рдФрд░ рддрджрдиреБрд╕рд╛рд░ рдХрд╛рд░реНрдпрд╢реАрд▓рддрд╛ рдХреЛ рдЬреЛрдбрд╝рд╛ рдЬреЛ рдЖрдкрдХреЛ рд╢реЙрдкрд┐рдВрдЧ рдХрд╛рд░реНрдЯ рдмрдирд╛рдиреЗ рдФрд░ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред

рдХрд╛рд░реНрдЯ рд╡рд┐рдЬреЗрдЯ



рдЦрд░реАрджрд╛рд░реА рдХреА рдЯреЛрдХрд░реА рдмрдирд╛рдиреЗ рдХрд╛ рддрдВрддреНрд░ рдХрд╛рдлреА рд╕рд░рд▓, рддрд╛рд░реНрдХрд┐рдХ рдФрд░ рдЗрд╕рд▓рд┐рдП рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ:
рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдкреЗрдбрд╝ рдореЗрдВ

рдЖрдк рд╢реНрд░реЗрдгреА рдХреЗ рднреАрддрд░ рдХрдИ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ "рдХрд╛рд░реНрдЯ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ" рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рддреЗ рд╣реИрдВред рд░реВрдЯ рд╢реНрд░реЗрдгреА рдХреЗ рд╕рд╛рде рдкрджреЛрдВ рдХреА рдпрд╣ рд╕реВрдЪреА рдПрдХ рд╡рд┐рдЬреЗрдЯ рдХрд╛рд░реНрдб рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрддреА рд╣реИред рдЗрд╕ рдХреНрд░рд┐рдпрд╛ рдХреЛ рдЖрд╡рд╢реНрдпрдХрддрд╛рдиреБрд╕рд╛рд░ рдХрдИ рдмрд╛рд░ рджреЛрд╣рд░рд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдирддреАрдЬрддрди, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рддрд╛рд░реНрдХрд┐рдХ рд░реВрдк рд╕реЗ рдЦрд░реАрджрд╛рд░реА рдХреА рд╕реВрдЪреА рд╣реИред
рд╕реБрдВрджрд░рддрд╛ рдпрд╣ рд╣реИ рдХрд┐ рдпрд╣ рддреБрд░рдВрдд рд╕рдореВрд╣ рдХреЗ рд╕рднреА рд╕рджрд╕реНрдпреЛрдВ рдореЗрдВ рджрд┐рдЦрд╛рдИ рджреЗрддрд╛ рд╣реИ, рдЕрд░реНрдерд╛рддред рдорд╛рдБ рдиреЗ рдХрд╛рд░реНрдб рдмрдирд╛рдП, рдФрд░ рдкрд┐рддрд╛рдЬреА рдиреЗ рд░рд╛рд╕реНрддреЗ рд╕реЗ рд╣рдЯрдХрд░ рд╕рдм рдХреБрдЫ рдЦрд░реАрдж рд▓рд┐рдпрд╛ред
рдХрд╛рд░реНрдб рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ рдФрд░ рд░рд╛рд╢рд┐ рджрд░реНрдЬ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлреЙрд░реНрдо рдЦреБрд▓ рдЬрд╛рддрд╛ рд╣реИред рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдкреНрд░рддреНрдпреЗрдХ рдЖрдЗрдЯрдо рдХреЗ рд▓рд┐рдП рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рдореВрд▓ рд╢реНрд░реЗрдгреА рдХреЗ рд▓рд┐рдП рд░рд╛рд╢рд┐ рджрд░реНрдЬ рдХрд░реЗрдВред рдпрд╛рдиреА рд╡рд┐рдЪрд╛рд░ рдпрд╣ рд╣реИ рдХрд┐ рд╣рдо рдЦрд░реАрдж рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╕реНрддреГрдд рд╢реНрд░реЗрдгрд┐рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рд░рд╛рд╢рд┐ рдХреЛ рдореВрд▓ рд╢реНрд░реЗрдгреА рджреНрд╡рд╛рд░рд╛ рдЕрдзрд┐рдХ рдореЛрдЯреЗ рддреМрд░ рдкрд░ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрд╛ рдЬрд╛рддрд╛ рд╣реИред


рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди

1. рд╕реЗрд╡рд╛ рдХрд╛ рд╡рд░реНрдЧ
public class StackWidgetService extends RemoteViewsService { @Override public void onCreate() { super.onCreate(); } @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new StackRemoteViewsFactory(this.getApplicationContext(), intent); } } 


2. рдХрд╛рд░реНрдб рд╕реНрдЯреИрдХ рдХреЗ рд▓рд┐рдП рдПрдбрд╛рдкреНрдЯрд░ рдХреНрд▓рд╛рд╕
 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. рд╡рд┐рдЬреЗрдЯ рдкреНрд░рджрд╛рддрд╛ рд╡рд░реНрдЧ
        .       -  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. рд╡рд┐рдЬреЗрдЯ рд▓реЗрдЖрдЙрдЯ
 <?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. рдХрд╛рд░реНрдб рдорд╛рд░реНрдХрдЕрдк
 <?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. рдПрдХреНрд╕рдПрдордПрд▓ рдкреНрд░рджрд╛рддрд╛ рд╡рд┐рд╡рд░рдг
 <?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/hi452998/


All Articles