invisible view toolbar action - eclipse-plugin

I wanted to make invisible some action added to the view toolbar based on perspective change.
Following is my code for making a particular action invisible. This code does not give me any effect.
The code executes fine, but it does not disappear from the toolbar.
IContributionItem[] items = view.getToolbar().getItems();
for (IContributionItem item : items) {
if (item instanceof ActionContributionItem) {
ActionContributionItem actionItem = (ActionContributionItem) item;
if(actionItem.getAction().getId().equals("actionid")){
//view.getToolbar().remove("actionid");
actionItem.setVisible(false);
}
}
}

You need to call the update() method on the toolbar manager.
See this snippet where an item gets invisible after 5 seconds:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
final ToolBarManager toolBarManager = new ToolBarManager();
final Action action1 = new Action("1") {
};
action1.setId("1");
toolBarManager.add(action1);
final Action action2 = new Action("2") {
};
action2.setId("2");
toolBarManager.add(action2);
toolBarManager.createControl(shell);
display.timerExec(5000, new Runnable() {
#Override
public void run() {
final IContributionItem[] items = toolBarManager.getItems();
for (IContributionItem item : items) {
if (item.getId().equals("1")){
item.setVisible(false);
}
}
toolBarManager.update(true);
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}

Related

Codename One location sometimes not working

Old question: Codename One app not provide real location
We still have problem getting current location.
Sometimes it's ok, "Localizzazione..." dialog shows, then location ok callback dispose the dialog.
Sometimes the dialog is never disposed and I don't see GPS in the top bar, which is visible when location is ok and dispose the dialog.
Slider s1 = new Slider();
Display.getInstance().callSerially(() -> {
blocco_loc_in_corso = makeDialog("Localizzazione...", s1, null, 'a');
blocco_loc_in_corso.show();
});
LocationManager locationManager = LocationManager.getLocationManager();
locationManager.setLocationListener(new LocationListener() {
#Override
public void locationUpdated(Location location) {
if(location != null) {
Display.getInstance().callSerially(() -> {
if(blocco_loc_in_corso != null) {
blocco_loc_in_corso.dispose();
}
});
paintLocation(location, true);
}
}
#Override
public void providerStateChanged(int newState) {
}
}, new LocationRequest(LocationRequest.PRIORITY_HIGH_ACCUARCY, 1000));
I have this problem for at least 6 months. We only need to block user until we have his GPS location which may can change (GPS updates callback).
Edited:
public Dialog makeDialog(String label, Component c, String buttonText, char btIcon) {
Dialog dlg_r = new Dialog();
Style dlgStyle = dlg_r.getDialogStyle();
dlgStyle.setBorder(Border.createEmpty());
dlgStyle.setBgTransparency(255);
dlgStyle.setBgColor(0xffffff);
Label title = dlg_r.getTitleComponent();
title.getUnselectedStyle().setFgColor(0xff);
title.getUnselectedStyle().setAlignment(Component.LEFT);
dlg_r.setLayout(BoxLayout.y());
Label blueLabel = new Label(label);
blueLabel.setShowEvenIfBlank(true);
blueLabel.getUnselectedStyle().setBgColor(0xff);
blueLabel.getStyle().setFgColor(0x0a0afc);
blueLabel.getStyle().setAlignment(Component.CENTER);
blueLabel.getUnselectedStyle().setPadding(1, 1, 1, 1);
blueLabel.getUnselectedStyle().setPaddingUnit(Style.UNIT_TYPE_PIXELS);
dlg_r.add(blueLabel);
dlg_r.add(c);
if (buttonText != null) {
Button dismiss = new Button(buttonText);
dismiss.getAllStyles().setBorder(Border.createEmpty());
dismiss.getAllStyles().setFgColor(0);
dismiss.getAllStyles().set3DText(true, true);
dismiss.setIcon(FontImage.createMaterial(btIcon, dismiss.getStyle()));
dismiss.addActionListener(((evt) -> {
dlg_r.dispose();
}));
dlg_r.add(dismiss);
}
return dlg_r;
}
To make sure this code is threadsafe make the following change:
public void locationUpdated(Location location) {
locationFound = true;
// ...
}
Then in the make dialog method:
dlg_r.addShowListener(e -> {
if(locationFound) {
dlg_r.dispose();
}
});
Since this event can happen in the dead time of showing the dialog transition.

How to check if an application is it's first run or not in xamarin crosspaltform

I want to show some pages in the first time app is installed, and the next time when I open the app show some other pages.
I tried this code
protected override void OnStart()
{
if (Application.Current.Properties.ContainsKey("id"))
{
MainPage = new NavigationPage(new Page2());
}
else
{
Application.Current.Properties["id"] = 2;
MainPage = new NavigationPage(new Page1());
}
}
The values in the Properties dictionary are only stored when the app goes to sleep
For a cross-platform approach, you can use the Settings Plugin
Then you can create a boolean property, for example, DidOpenOnce, and if it is false, show your initial welcome page or whatever. Then afterwards, set it to true.
protected void checkApplicationInstallState()
{
//retreive
var prefs = Application.Context.GetSharedPreferences("MyApp", FileCreationMode.Private);
var somePref = prefs.GetBool("IsApplicationOpenedForOnce", null);
if (!somePref) {
// Your Application is opened for the very first time. Now change the value to true as you have now opened the app so next time opening this application should get a true value.
var prefEditor = prefs.Edit();
prefEditor.PutBool(true, "IsApplicationOpenedForOnce");
prefEditor.Commit();
}
}
public MainPage()
{
InitializeComponent();
if (Application.Current.Properties.ContainsKey("FirstUse"))
{
//Do things when it's NOT the first use...
loadinit();
}
else
{
Application.Current.Properties["FirstUse"] = false;
//Do things when it IS the first use...
}
}
public async void loadinit()
{
await Navigation.PushAsync(new LoadPage());
}

pageState and viewModelState is null on Page Navigation in UWP

I am using Prism 6 with UWP. I have a button in MainPage.xaml which redirect to DashboardPage.xaml. In DashboardPage, I am saving the view state in DashboardPage.xaml.cs :
protected override void SaveState(Dictionary<string, object> pageState)
{
base.SaveState(pageState);
pageState["viewState"] = 123;
}
and saving view model state in DashboardPageViewModel.cs :
public override void OnNavigatingFrom(NavigatingFromEventArgs e, Dictionary<string, object> viewModelState, bool suspending)
{
base.OnNavigatingFrom(e, viewModelState, suspending);
}
[RestorableState]
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
By pressing back button from topbar, I went back to MainPage.xaml. After that, when I navigate to DashboardPage.xaml again, I found that view state and view model states are being null. Which means, in the below code of DashboardPage.xaml.cs
protected override void LoadState(object navigationParameter, Dictionary<string, object> pageState)
{
if (pageState == null)
{
return;
}
base.LoadState(navigationParameter, pageState);
if (pageState.ContainsKey("viewState"))
{
var data = pageState["viewState"].ToString();
}
}
pageState is found null.
And, for view model state in DashboardPageViewModel.cs :
public async override void OnNavigatedTo(NavigatedToEventArgs e, Dictionary<string, object> viewModelState)
{
base.OnNavigatedTo(e, viewModelState);
}
viewModelState is null
By pressing back button from topbar, I went back to MainPage.xaml. After that, when I navigate to DashboardPage.xaml again, I found that view state and view model states are being null.
From your posted project. I found that you use NavigationService.Navigate to navigate to DashboardPage. It's right at first time, but after you navigating back to MainPage and again navigate back to DashboardPage. You are also using the NavigationService.Navigate API.
I downloaded Prism's Source Codes and found where the LoadState is called:
protected override void OnNavigatedTo(NavigationEventArgs navigationEventArgs)
{
...
if (navigationEventArgs.NavigationMode == NavigationMode.New)
{
var nextPageKey = _pageKey;
int nextPageIndex = frameFacade.BackStackDepth;
while (frameState.Remove(nextPageKey))
{
nextPageIndex++;
nextPageKey = "Page-" + nextPageIndex;
}
// Pass the navigation parameter to the new page
LoadState(navigationEventArgs.Parameter, null);
}
else
{
LoadState(navigationEventArgs.Parameter, (Dictionary<String, Object>)frameState[_pageKey]);
}
}
As you can see, the LoadState is called inside OnNavigatedTo and PageState is passed as argument on condition that the NavigationMode is not New. For ViewModelState it is the similar situation. And for your case, everytime navigating to a page through NavigationService.Navigate will create a totally new page, which means NavigationMode=NavigationMode.New. Therefore PageState and ViewModelState are null.
From the NavigationMode document we can see the NavigationMode.Forward fits your requirement.
So, to fix the problem. The only thing that needs to be done is to modify the OnPageChange method in MainPageViewModel.cs like codes below:
private void OnPageChange()
{
if (_navigationService.CanGoForward())
{
_navigationService.GoForward();
}
else
{
_navigationService.Navigate("Dashboard", null);
}
}

Recycler View: Inconsistency detected. Invalid view holder adapter positionViewHolder

Recycler View Inconsistency Detected error, coming while scrolling fast or scrolling while loading more items..
FATAL EXCEPTION: main
Process: com.pratap.endlessrecyclerview, PID: 21997
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{56a082c position=40 id=-1, oldPos=39, pLpos:39 scrap [attachedScrap] tmpDetached no parent}
at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4251)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4382)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4363)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1961)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1370)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1333)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:562)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2864)
at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1445)
at android.support.v7.widget.RecyclerView.access$400(RecyclerView.java:144)
at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:282)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:603)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:746)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5443)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
Adapter
public class DataAdapter extends RecyclerView.Adapter {
private final int VIEW_ITEM = 1;
private final int VIEW_PROG = 0;
private List<Feed> mFeed;
// The minimum amount of items to have below your current scroll position
// before loading more.
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
private boolean loading;
private OnLoadMoreListener onLoadMoreListener;
public DataAdapter(List<Feed> feeds, RecyclerView recyclerView) {
mFeed = feeds;
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView
.getLayoutManager();
recyclerView
.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView,
int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager
.findLastVisibleItemPosition();
if (!loading
&& totalItemCount <= (lastVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
if (onLoadMoreListener != null) {
onLoadMoreListener.onLoadMore();
}
loading = true;
}
}
});
}
}
#Override
public int getItemViewType(int position) {
return mFeed.get(position) == null ? VIEW_PROG : VIEW_ITEM;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
RecyclerView.ViewHolder vh;
if (viewType == VIEW_ITEM) {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.list_row, parent, false);
vh = new StudentViewHolder(v);
}
else {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.progress_item, parent, false);
vh = new ProgressViewHolder(v);
}
return vh;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof StudentViewHolder) {
Feed singleStudent= (Feed) mFeed.get(position);
((StudentViewHolder) holder).tvName.setText(singleStudent.getTitle());
((StudentViewHolder) holder).student= singleStudent;
} else {
ProgressViewHolder.PROGRESS_BAR.setIndeterminate(true);
}
}
public void setLoaded() {
loading = false;
}
public void addFeed(Feed feed) {
mFeed.add(feed);
//mFeed.addAll(0, (Collection<? extends Feed>) feed);
notifyItemInserted(mFeed.size());
//notifyItemRangeInserted(0,mFeed.size());
notifyDataSetChanged();
//notifyItemInserted(mFeed.size());
//setLoaded();
//notifyItemInserted(mFeed.size());
}
public void removeAll(){
mFeed.clear();
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return mFeed.size();
}
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.onLoadMoreListener = onLoadMoreListener;
}
public static class StudentViewHolder extends RecyclerView.ViewHolder {
public TextView tvName;
public Feed student;
public StudentViewHolder(View v) {
super(v);
tvName = (TextView) v.findViewById(R.id.tvName);
//tvEmailId = (TextView) v.findViewById(R.id.tvEmailId);
}
}
public static class ProgressViewHolder extends RecyclerView.ViewHolder {
//public ProgressBar progressBar;
public static ProgressBar PROGRESS_BAR;
public ProgressViewHolder(View v) {
super(v);
PROGRESS_BAR = (ProgressBar) v.findViewById(R.id.progressBar1);
// progressBar = (ProgressBar) v.findViewById(R.id.progressBar1);
}
}
}
Activity
public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {
private Toolbar toolbar;
private TextView tvEmptyView;
private RecyclerView mRecyclerView;
private DataAdapter mAdapter;
private LinearLayoutManager mLayoutManager;
private RestManager mManager;
private List<Feed> mFeed;
SwipeRefreshLayout mSwipeRefreshLayout;
protected Handler handler;
private int currentPage=1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
tvEmptyView = (TextView) findViewById(R.id.empty_view);
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
mSwipeRefreshLayout= (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
mSwipeRefreshLayout.setOnRefreshListener(this);
//studentList = new ArrayList<Student>();
mFeed = new ArrayList<Feed>();
handler = new Handler();
if (toolbar != null) {
setSupportActionBar(toolbar);
getSupportActionBar().setTitle("Android Students");
}
mManager = new RestManager();
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
// use a linear layout manager
mRecyclerView.setLayoutManager(mLayoutManager);
// create an Object for Adapter
mAdapter = new DataAdapter(mFeed,mRecyclerView);
// set the adapter object to the Recyclerview
mRecyclerView.setAdapter(mAdapter);
// mAdapter.notifyDataSetChanged();
loadData(false);
// if (mFeed.isEmpty()) {
// mRecyclerView.setVisibility(View.GONE);
// tvEmptyView.setVisibility(View.VISIBLE);
//
// } else {
// mRecyclerView.setVisibility(View.VISIBLE);
// tvEmptyView.setVisibility(View.GONE);
// }
mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
//add null , so the adapter will check view_type and show progress bar at bottom
mFeed.add(null);
mAdapter.notifyItemInserted(mFeed.size() - 1);
handler.postDelayed(new Runnable() {
#Override
public void run() {
// remove progress item
mFeed.remove(mFeed.size() - 1);
// mAdapter.notifyItemRemoved(mFeed.size());
//add items one by one
int start = mFeed.size();
currentPage++;
Log.d("CurrentPage", String.valueOf(currentPage));
Call<Results> listCall = mManager.getFeedApi().getAllFeeds(1);
listCall.enqueue(new Callback<Results>() {
#Override
public void onResponse(Call<Results> call, Response<Results> response) {
mSwipeRefreshLayout.setRefreshing(false);
if (response.isSuccess()) {
if (response.body() != null) {
Results feedList = response.body();
// List<Results> newUsers = response.body();
Log.d("Retrofut", String.valueOf(feedList));
for (int i = 0; i < feedList.results.size(); i++) {
Feed feed = feedList.results.get(i);
// mFeed.add(feed);
mAdapter.addFeed(feed);
// mAdapter.notifyDataSetChanged();
//mAdapter.notifyItemInserted(mFeed.size());
}
// mAdapter.notifyDataSetChanged();
}
}
}
#Override
public void onFailure(Call<Results> call, Throwable t) {
Log.d("Retrofut", "Error");
mFeed.remove(mFeed.size() - 1);
mAdapter.notifyItemRemoved(mFeed.size());
mAdapter.setLoaded();
mSwipeRefreshLayout.setRefreshing(false);
}
});
// for (int i = 1; i <= 20; i++) {
// studentList.add(new Student("Student " + i, "androidstudent" + i + "#gmail.com"));
//
// }
mAdapter.setLoaded();
//or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged();
}
}, 2000);
}
});
}
// load initial data
private void loadData(final boolean removePreData) {
Call<Results> listCall = mManager.getFeedApi().getAllFeeds(1);
listCall.enqueue(new Callback<Results>() {
#Override
public void onResponse(Call<Results> call, Response<Results> response) {
if (response.isSuccess()) {
if (response.body() != null) {
// if(removePreData) mAdapter.removeAll();
Results feedList = response.body();
Log.d("Retrofut", String.valueOf(feedList));
for (int i = 0; i < feedList.results.size(); i++) {
Feed feed = feedList.results.get(i);
// mFeed.add(feed);
//mAdapter.notifyDataSetChanged();
mAdapter.addFeed(feed);
}
mSwipeRefreshLayout.setRefreshing(false);
}
}
}
#Override
public void onFailure(Call<Results> call, Throwable t) {
Log.d("Retrofut", String.valueOf(t));
mFeed.remove(mFeed.size() - 1);
mAdapter.notifyItemRemoved(mFeed.size());
mAdapter.setLoaded();
mSwipeRefreshLayout.setRefreshing(false);
}
}
);
// for (int i = 1; i <= 20; i++) {
// studentList.add(new Student("Student " + i, "androidstudent" + i + "#gmail.com"));
//
// }
mSwipeRefreshLayout.setRefreshing(true);
}
#Override
public void onRefresh() {
mFeed.clear();
mAdapter.notifyDataSetChanged();
loadData(true);
currentPage=1;
}
}
put this line along with setting recyclerView. issue was fixed by
setting ItemAnimator to null for RecyclerView.
in kotlin
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.itemAnimator = null
in java
recyclerView.setItemAnimator(null);
It looks similar with known android bug
There are quite ugly, but working approach
public class WrapContentLinearLayoutManager extends LinearLayoutManager {
//... constructor
#Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
} catch (IndexOutOfBoundsException e) {
Log.e("Error", "IndexOutOfBoundsException in RecyclerView happens");
}
}
}
mRecyclerView.setLayoutManager(new WrapContentGridLayoutManager(getContext(), spanCount));
For me it works without any by-effect.
This issue is a known bug of RecyclerView. The best solution is, clear the list every time before refresh RecyclerView.
For fix this issue just call notifyDataSetChanged() with empty list before updating recycle view.
For example
//Method for refresh recycle view
if (!yourList.isEmpty())
yourList.clear(); //The list for update recycle view
adapter.notifyDataSetChanged();
Use this to refresh a RecyclerView
items.clear(); //here items is an ArrayList populating the RecyclerView
adapter.notifyDataSetChanged();
items.addAll(list);// add new data
adapter.notifyItemRangeInserted(0, items.size);// notify adapter of new data
`
I had similiar issue, and also this solution has helped me, after I've added new item to my RV:
recyclerView.getRecycledViewPool().clear();
adapter.notifyDataSetChanged();
Maybe you can try this before refresh the adapter:
dataList.clear();
patrolListAdapter.notifyDataSetChanged();
In my case I was doing it as notifyItemInserted(position);
That caused me this issue then i used as and it worked perfectly.notifyItemRangeInserted(startIndex,endIndex);
I had this problem when scrolling fast through my endless/paging RecyclerView. The root of my problem came from the fact that I had a “header” item at the beginning of the list, this header item was not a part of the data source, it was just inserted at the beginning of the adapter list. So when scrolling fast and adding new pages of items to the RecyclerView Adapter and notify the adapter that new data had been inserted, I was not taking into account the additional header item, thus making the size of the adapter’s list wrong... and causing this exception...
So in short, if you’re using a header/footer in our RecyclerView adapter make sure you take it into account when updating the adapters data.
Example:
public void addNewPageToList(List<MyData> list)
{ //
// Make sure you account for any header/footer in your list!
//
// Add one to the currentSize to account for the header item.
//
int currentSize = this.adapterList.size() + 1;
this.adapterList.addAll(list);
notifyItemRangeInserted(currentSize, this.adapterList.size());
}
Edit:
I guess you could always just use the adapter method getItemCount() to get the size, instead of getting the size from the “data list” and adding to it. Your getItemCount() method should already be taking into account any additional headers/footers/etc that you have in your list.
The problem is in this line of code:
mFeed = feeds;
you are assigning mFeed to the caller's instance feeds so whenever the caller changes it's variable (may be adding, clearing or removing items), your local mFeed will change
try to change to
mFeed.addAll(feeds);
don't forget to initialize mFeed to any list tat fits your needs like mFeed = new ArrayList<>();
put this line along with setting recyclerView. issue was fixed by setting ItemAnimator to null for RecyclerView.
in kotlin
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.itemAnimator = null
I'm using the recyclerview from mikepenz. And any update to the items using .set(item) was causing this issue.
For some reason, setting recylerView.itemAnimator = null, resolved the issue. This is a known android bug.
In my case, I was using RecyclerView from Firebase UI. Initially, the logic to initialize the RecyclerView was in onCreate(). To fix, I put the logic in onResume() and seems to be working for me. I had this error when going back to the Activity which had the RecyclerView. So, everytime the Activity screen is refreshed, the new data is loaded.
I had similar problem. Removing all views from RecyclerView helped me:
RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager();
layoutManager.removeAllViews();
For me the issue was I wasn't posting notifyDatasetChanged when the data set changed as I implemented incremental search.
I had a list that was filtered based on what the user searched in the search widget. For each item in the list, I was making a remote request, and when I got the result back, I was updating that particular cell.
I had to do both notifies for the recycler view to work
Filter the original data set then post the dataset change
this.searchResultTable?.post {
this.searchResultTable?.adapter?.notifyDataSetChanged()
}
After receiving response, post notifications again
this.searchResultTable?.post {
this.searchResultTable?.adapter?.notifyItemChanged(index, updateDataHashMap)
}
You have to post updates rather than sending notifiy messages directly in order to prevent the recycler view from crashing when the update comes in before the view is laid out.
Another important gotcha is that when you post the individual updates after the remote response, you have to make sure that the list the user currently sees is the list that existed when the requests were sent.
For my case in adapter there was notifyItemRangeInserted and I replaced it with notifyItemRangeChanged

Xamarin Forms Switch XAML

I'm new in Xamarin and i'm trying to create a simple page with some components.
One of these component is a Switch it works fine by itself but i would like to change the basic text "inactive/active" by "male/female"
I've seen that in Xaml for windows phone there is a ToggleSwitch Component with a On/OffContent property but i can't seems to find an equivalent in XAML for Xamarin Forms
any idea ?
Thank you!
The lack of built in switch options, or at least the lack of being able to rename the switch options, has been asked a few times.
You could go with custom renders, modify the text at the OS level or do like I chose to do, just build your own switch.
This switch is two buttons laid out horizontally with the text Yes and No. The selected button gets a red border, and the unselected a transparent border.
class CustomSwitch : Grid
{
public event EventHandler<SelectedItemChangedEventArgs> ItemSelected;
private Button negative;
private Button positive;
public static readonly BindableProperty SelectedItemProperty = BindableProperty.Create<CustomSwitch, Object>(t => t.SelectedItem, null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged);
public CustomSwitch()
{
try
{
this.HorizontalOptions = LayoutOptions.Center;
this.VerticalOptions = LayoutOptions.Center;
negative = new Button();
negative.Text = "No";
negative.Style = <YourNameSpace>.AppStyling.Style_Button_Switch;
negative.Clicked += (o,s) => OnSelectedItemChanged(this, ItemSelected, (int)Classes.Collections.Enums.SelectionStatus.False);
positive = new Button();
positive.Text = "Yes";
positive.Style = <YourNameSpace>.AppStyling.Style_Button_Switch;
positive.Clicked += (o, s) => OnSelectedItemChanged(this, ItemSelected, (int)Classes.Collections.Enums.SelectionStatus.True);
this.Children.Add(negative, 0,0);
this.Children.Add(positive, 1,0);
}
catch(System.Exception ex)
{
<YourNameSpace>.Classes.Helpers.Helper_ErrorHandling.SendErrorToServer(ex, this.GetType().Name, System.Reflection.MethodBase.GetCurrentMethod().Name);
}
}
public Object SelectedItem
{
get
{
return base.GetValue(SelectedItemProperty);
}
set
{
if (SelectedItem != value)
{
base.SetValue(SelectedItemProperty, value);
InternalUpdateSelected();
}
}
}
private void InternalUpdateSelected()
{
if((int)SelectedItem == (int)Classes.Collections.Enums.SelectionStatus.False)
{
negative.BorderColor = <YourNameSpace>.AppStyling.Color_Selected;
positive.BorderColor = <YourNameSpace>.AppStyling.Color_UnSelected;
positive.Opacity = <YourNameSpace>.AppStyling.Opaque_High;
}
else if ((int)SelectedItem == (int)Classes.Collections.Enums.SelectionStatus.True)
{
negative.BorderColor = <YourNameSpace>.AppStyling.Color_UnSelected;
negative.Opacity = <YourNameSpace>.AppStyling.Opaque_High;
positive.BorderColor = <YourNameSpace>.AppStyling.Color_Selected;
}
else
{
negative.BorderColor = <YourNameSpace>.AppStyling.Color_UnSelected;
negative.Opacity = <YourNameSpace>.AppStyling.Opaque_High;
positive.BorderColor = <YourNameSpace>.AppStyling.Color_UnSelected;
positive.Opacity = <YourNameSpace>.AppStyling.Opaque_High;
}
}
private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
{
CustomSwitch boundSwitch = (CustomSwitch)bindable;
if((int)newValue != (int)Classes.Collections.Enums.SelectionStatus.Unselected)
{
boundSwitch.SelectedItem = (int)newValue == (int)Classes.Collections.Enums.SelectionStatus.False ? (int)Classes.Collections.Enums.SelectionStatus.False : (int)Classes.Collections.Enums.SelectionStatus.True;
}
if (boundSwitch.ItemSelected != null)
{
boundSwitch.ItemSelected(boundSwitch, new SelectedItemChangedEventArgs(newValue));
}
boundSwitch.InternalUpdateSelected();
}
}