I'm using https://github.com/etsy/AndroidStaggeredGrid/ in my project. Everything works fine, except I can't scroll it to specific position/item at will.
What I've tried so far (everything I could think of, enclosed in one piece of code for you to look at):
final StaggeredGridView gv = (StaggeredGridView) ma.findViewById(R.id.photosList);
gv.setChoiceMode(StaggeredGridView.CHOICE_MODE_SINGLE);
gv.setFocusable(true);
gv.clearFocus();
gv.post( new Runnable() {
#Override
public void run() {
// #1 approach
gv.requestFocusFromTouch();
gv.smoothScrollToPosition(index);
// #2 approach
gv.setSelection(index);
View v = gv.getChildAt(index);
if (v != null) {
// #3 approach
v.requestFocus();
}
//v.requestFocusFromTouch();
Utils.log("scroll to " + index);
gv.requestLayout();
}
});
Nothing seems to work and I'm begining to think this view has some kind of bug related to my issue. Is there someone who can help me in the matter?
I found that I wasn't able to scroll to a specific location, however, I did find that I was able to restore the state of the gridview. In my application I had to implement a custom back stack mechanism, and you can pass the state which you can get from:
Parcelable state = mgridView.onSaveInstanceState();
The state is a Parcelable, so i was able to putParcelable in an intent, and then retrieve it and restore the state as needed, like so
if(state != null) {
mgridView.onRestoreInstanceState(state);
}
Upon restoring the state, it restores the previous position in the grid exactly.
Hope this helps anyone else facing this issue!
Related
I know Piccolo2d is an old project, but I have a couple of questions.
1) Is it possible to disable dragging a selected object? For this particular use case, I only want to select an object, not move or delete it. I know I can disable deletion using:
this.selector.setDeleteKeyActive(false);
But I don't see an option to disable dragging. Is the only option to override the drag functionality in the event handler?
2) Is there no way to have the selection handler active at the same time as the pan/zoom handlers? It seems a bit archaic to disable pan/zoom when you want to support object picking. Or do I have to create my own handlers?
My current code is:
...
this.pluginContext.getCanvas().setPanEventHandler(null);
this.selector = new PSelectionEventHandler(this.mapLayer.getNode(), this.mapLayer.getNode()) {
};
this.selector.setDeleteKeyActive(false);
this.pluginContext.getCanvas().addInputEventListener(this.selector);
PNotificationCenter.defaultCenter().addListener(this, "nodeSelected",
PSelectionEventHandler.SELECTION_CHANGED_NOTIFICATION, this.selector);
...
public void nodeSelected(final PNotification notification) {
logger.debug("Selection - " + this.selector.getSelection().toString());
}
In true developer tradition, I found an answer.
My pickable nodes are all grouped under individual grouping nodes. This lets me add an event listener on the grouping node, like this:
groupNode.addInputEventListener(new PBasicInputEventHandler() {
public void mouseReleased(final PInputEvent event) {
PNode node = event.getPickedNode();
if (node != null) {
onNodeSelected(node); // your logic here
}
}
});
The beauty of this is that the event contains the picked node that is grouped under that group node. Perfect! Also, you don't have to disable the pan/zoom handlers.
The only downside is that this doesn't give you the selection decorator around the node. Can't win 'em all!
This is more of a general question. We have a lot of wizard, some of which start a long-running process and display the result after. The question is: what is the correct way to do long calculations?
Formerly most wizards did their calculations in DialogPage#setVisible, something like that:
public void setVisible(final boolean visible) {
if (visible) {
getWizard().getContainer().run(true, true, new MyCalculation());
}
super.setVisible(visible);
}
I don't think that's a good idea, since usually getWizard() gets called a lot in these methods. Moreover, usually the parent wizard gets cast to a specific implementation to get input values from or set the result to other pages. So usually it looks something like this:
public void setVisible(final boolean visible) {
if (visible) {
Input input = ((MyCalculationWizard)getWizard()).getInputPage().getInput();
MyCalculation calculation = new MyCalculation(input);
getWizard().getContainer().run(true, true, calculation);
Output output = calculation.getOutput();
((MyCalculationWizard)getWizard()).getOtherPage().setOutput(output);
}
super.setVisible(visible);
}
Just from looking at the code you know that's very bad style.
So we replaced it with something that calculates in Wizard#getNextPage():
public IWizardPage getNextPage(final IWizardPage page) {
final IWizardPage nextPage = super.getNextPage(page);
if (nextPage == this.myResultPage)
getContainer().run(true, true, new MyCalculation());
return nextPage;
}
That way, the wizard is able to fine-tune a lot better than a page would, and the wizard already knows it's pages and can handle input and output a lot better than a page ever could.
The drawback is: getNextPage() gets called a lot for updating the buttons and every time really the wizard feels like it. So while it works for small processes, it does not cut it for long-running ones.
After some more poking around I found the following to work while overriding Wizard#setContainer:
public void setContainer(final IWizardContainer wizardContainer) {
final IWizardContainer oldContainer = getContainer();
if (oldContainer instanceof WizardDialog)
((WizardDialog) oldContainer).removePageChangingListener(this);
super.setContainer(wizardContainer);
if (wizardContainer instanceof WizardDialog)
((WizardDialog) wizardContainer).addPageChangingListener(this);
}
public void handlePageChanging(final PageChangingEvent event) {
final IWizardPage currentPage = (IWizardPage) event.getCurrentPage();
final IWizardPage nextPage = (IWizardPage) event.getTargetPage();
if (currentPage == this.myInputPage && nextPage == this.myResultPage)
getContainer().run(true, true, new MyCalculation());
}
The big advantage here is that the listener only gets called if the wizard wants to jump between pages, and we are able to really fine-tune the calculation (e.g. to not be called when calling 'Previous'). We are even able to not show the next page after all (event.doit = false).
The drawback is the cast of the container to WizardDialog, because potentially it could be an entirely different implementation.
So the question stands: What is the best way to start long processes in wizards?
Sorry I can't come up with a better question title because it's pretty hard to describe...
I was inspecting Android's source (4.4 KK), the View class in particular and this showed up:
// .... lots of stuff....
AttachInfo mAttachInfo;
// .... lots of stuff....
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().post(action);
return true;
}
That's the View.post(Runnable) that we all love to use whenever we need something to run on the UI thread.
The thing I don't understand here is why do they create another local reference of attachInfo?
Why don't they do it like:
if (mAttachInfo != null) {
return mAttachInfo.mHandler.post(action);
}
Other than making attachInfo immutable in the method scope to prevent bugs(even thought they can still accidentally access mAttachInfo), I don't think there's any reason to do this.
Another possibility would be to shorten names, but I don't think it's worth shorting 1 character.
Is this a design pattern?
EDIT:
further inspecting the source reveals that they use this "pattern" in many places:
public void postInvalidateOnAnimation() {
// We try only with the AttachInfo because there's no point in invalidating
// if we are not attached to our window
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this);
}
}
Basically, they use it in almost every postXXXXXX() method.
EDIT2:
#CommonsWare pointed out that it might be used for anonymous inner class in previous versions, I checked the source of 1.5(Cupcake) ~ 2.3.3(Gingerbread) and this is what post() looks like
public boolean post(Runnable action) {
Handler handler;
if (mAttachInfo != null) {
handler = mAttachInfo.mHandler;
} else {
// Assume that post will succeed later
ViewRoot.getRunQueue().post(action);
return true;
}
return handler.post(action);
}
I still don't see why....
Bear in mind that post() may be called from background threads at the same time as mAttachInfo is updated on the UI thread. The code that was used up to Android 2.3.3 could throw an NPE if mAttachInfo was set to null after the if (mAttachInfo != null) check and before mAttachInfo.mHandler was accessed.
The current code avoids the NPE by taking a snapshot of mAttachInfo that doesn't change for the lifetime of the method.
The local variable doesn't strictly need to be final, but declaring it final makes it extra clear that it won't become null after the if (attachInfo != null) check.
I am trying to allow my user to search through a table of information, dynamically hiding/showing results that contain the search. I have the hiding part down, and it works well, but I'm having trouble showing the table item again once the search criteria is changed.
Here is my hide code:
searchField.addModifyListener(new ModifyListener() {
#Override
public void modifyText(ModifyEvent arg0) {
modified = true;
for (int i = 0; i < table.getItems().length; i++) {
if (!(table.getItem(i).getText(2)
.contains(searchField.getText()))) {
table.getItem(i).dispose();
}
}
if ("".equals(searchField.getText())) {
modified = false;
//where I would want to un-hide items
}
}
});
Looking at your code, it seems you try to hide the item by calling dispose(). If you dispose a widget, it is gone for good. You cannot get it back.
If you want to unhide it again, will have to create a new item at the position of the previously hidden one with the same content.
Isn't it better to actually operate with some kind of a table model and JFace bindings, rather, then do it like that? And yes, disposing is not hiding. You should probably remove the item from the table.
You have probably to save the data from TableItem into collection before you call dispose. Then when you search again you could check that collection and if matches are found, then insert back into Table by creating new TableItem.
I am working on a project using Synth for the UI and want to implement some custom buttons. The buttons need to make use of style settings from a synth XML settings file - e.g. font colors which are different for different states (MOUSE_OVER, PRESSED, etc).
The problem I'm stuck on is that some of the buttons need to have extra sub-components - e.g. some need more than one label. I want the sub-components to pick up the same style settings as the standard button sub-components.
I feel like I ought to be able to just extend JButton and override/extend paintComponent to call the draw methods of some child components. I'm a bit unsure about a few aspects of that approach though: e.g. what parameters to pass to paintComponent; and how to ensure the sub-components get the correct Synth style settings (particularly wrt. the states).
An aside: I have tried extending JPanel but have run into some difficulties with that approach (see here: JPanel states for Synth).
EDIT: So, I've discovered that it is possible to add sub-components to buttons and have them render correctly. It seems that even though JButton.getLayout() returns null, the button will use an OverlayLayout unless you call JButton.setLayout(). Calling JButton.setLayout(null) does prevent the OverlayLayout being used, so that's how I'm handling the layout.
I'm looking into a couple of different approaches to updating the styles for the child controls, will report back on those later.
So, in case it's of use to anyone else here's the approach I took in the end:
class CustomButton extends JButton {
CustomButton() {
// ... normal button init
// Enable absolute positioning of sub-components.
setLayout(null);
updateStyles();
getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
updateStyles();
}
});
}
private void updateStyles() {
// See below for implementation.
}
private int getSynthComponentState() {
// This is basically a copy of SynthButtonUI.getComponentState(JComponent)
int state = SynthConstants.ENABLED;
if (!isEnabled()) {
state = SynthConstants.DISABLED;
}
if (model.isPressed()) {
if (model.isArmed()) {
state = SynthConstants.PRESSED;
} else {
state = SynthConstants.MOUSE_OVER;
}
}
if (model.isRollover()) {
state |= SynthConstants.MOUSE_OVER;
}
if (model.isSelected()) {
state |= SynthConstants.SELECTED;
}
if (isFocusOwner() && isFocusPainted()) {
state |= SynthConstants.FOCUSED;
}
if (isDefaultButton()) {
state |= SynthConstants.DEFAULT;
}
return state;
}
}
I found 2 approaches to how to implement the updateStyles() method: (A) change the name of the component to use a different named style, or (B) copy the style settings from the button to the sub-components. Approach (A) is pretty straightforward, approach (B) works as follows:
private void updateStyles() {
SynthStyle ss = SynthLookAndFeel.getStyle(this, Region.BUTTON);
SynthContext sc = new SynthContext(this, Region.BUTTON, ss, getSynthComponentState());
for (Component c : getComponents()) {
c.setFont(ss.getFont(sc));
c.setBackground(ss.getColor(sc, ColorType.BACKGROUND));
c.setForeground(ss.getColor(sc, ColorType.FOREGROUND));
// ... and so on if you have other style elements to be changed.
}
}
Approach (A) is probably better if you're changing more than a couple of style settings with each different state, although it could get unwieldy if you have different styles for a lot of different states. If you're only changing a couple of style settings (e.g. in my case I only care about colours, at least for now) then approach (B) seems best.
There's also the approach suggested by trashgod of implementing a custom UI delegate (extending BasicButtonUI) but if you take that route I think you'll have to re-implement much of SynthButtonUI.