I have created swiping tabs and have added a method to remove a given tab at a position . It works fine if I try to remove any tab other than current tab .In that case, the code throws IllegalStateException. PLease let me know what is my mistake .
Following is my code :
public class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
private final String TAG = "TABS_ADAPTER";
final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(FragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
public int getCount() {
return mTabs.size();
}
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
public void onPageScrollStateChanged(int state) {
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(tab.getPosition());
Log.v(TAG, "clicked");
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {}
public void onTabReselected(Tab tab, FragmentTransaction ft) {}
public void onTabReselected(Tab tab, android.app.FragmentTransaction ft) {}
#Override
public void onTabSelected(Tab tab, android.app.FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) {}
public void removeTab(ActionBar.Tab tab) {
mTabs.remove(tab.getTag());
mActionBar.removeTab(tab);
//mTabs.remove(mViewPager.getCurrentItem());
//mActionBar.removeTabAt(mViewPager.getCurrentItem());
notifyDataSetChanged();
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
// TODO Auto-generated method stub
super.destroyItem(container, position, object);
FragmentManager manager = ((Fragment) object).getFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
trans.remove((Fragment) object);
trans.commit();
}
}
Following is the logcat error :
06-26 15:57:00.149: E/AndroidRuntime(17064): FATAL EXCEPTION: main
06-26 15:57:00.149: E/AndroidRuntime(17064): java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 3, found: 2 Pager id: com.sparktg.weather:id/pager Pager class: class android.support.v4.view.ViewPager Problematic adapter: class com.sparktg.weather.TabsAdapter
I figured my mistake. I was trying to delete the current tab without providing an alternate tab to be displayed . In that schema of things, a user could have well deleted all the tabs , which is not advisable . Hence , in my removeTab() method of the adapter , I just set the current view to some default tab before deleting the current / any other tab . However , In such a scenario , the user should not have an option to delete that default tab .
Following is my improved method :
public void removeTab(ArrayList<String> tabNames){
Log.v(TAG, "Inside removeTab method of TabsAdpater");
Log.v(TAG, "Current Tab is at position " + mViewPager.getCurrentItem());
mViewPager.setCurrentItem(0);
Log.v(TAG, "Current Item is now set at position " + mViewPager.getCurrentItem());
for (int i=1; i<mTabNames.size(); i++){
for (int j=0;j<tabNames.size();j++){
if(tabNames.get(j).equals(mTabList.get(i).getText().toString())){
Log.v(TAG, "Tabs to be removed are : " + tabNames.get(j));
mTabs.remove(mTabList.get(i).getTag());
mActionBar.removeTab(mTabList.get(i));
mTabNames.remove(mTabList.get(i).getText());
mTabList.remove(mTabList.get(i));
notifyDataSetChanged();
}
}
}
}
Related
I want to open new activity that is different in each recyclerview item.
I have read and I do not need an image item here : How to open a different activity on recyclerView item onclick
This is my Adapter
public class B001Adapter extends RecyclerView.Adapter {
private Context context;
private LayoutInflater inflater;
List<B001Data> udata = Collections.emptyList();
public B001Adapter(Context context, List<B001Data> data) {
this.context = context;
inflater = LayoutInflater.from(context);
this.udata = data;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.datab001, parent, false);
MyHolder holder = new MyHolder(view);
return holder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
MyHolder myHolder = (MyHolder) holder;
final B001Data current = udata.get(position);
myHolder.device_name.setText(current.device_name);
myHolder.mac_address.setText(current.mac_address);
myHolder.status.setText("Status:" + String.valueOf(current.status));
}
#Override
public int getItemCount() {
return udata.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView device_name, mac_address, status;
public MyHolder(View itemView) {
super(itemView);
context = itemView.getContext();
device_name = (TextView) itemView.findViewById(R.id.txt_device_name);
mac_address = (TextView) itemView.findViewById(R.id.txt_mac_address);
status = (TextView) itemView.findViewById(R.id.txt_status);
}
public void onClick(AdapterView<?> parent, View view, int position {
final Intent intent;
switch (getAdapterPosition()){
case 0:
intent = new Intent(context, MainActivity.class);
break;
case 1:
intent = new Intent(context, B001FacilityM.class);
break;
case 2:
intent = new Intent(context, B001HRD.class);
break;
default:
intent = new Intent(context, B001home.class);
break;
}
context.startActivity(intent);
}
}
}
I use volley to get Json data displayed on the recyclerView. Looking for your advice. Thanks
First You Should assign id to layout file (R.layout.datab001),
find out id using findViewsById in MyHolder() constructor
and then set onClickListener to layout like myHolder.layout.setOnClickListener(....);
in onBindViewHolder().
or check other answer
RecyclerView onClick
public async override void OnActivityCreated (Bundle savedInstanceState)
{
base.OnActivityCreated (savedInstanceState);
lst = View.FindViewById<ListView> (Resource.Id.lstHome);
var result = await json.GetStringbyJson ("https://api-v2.soundcloud.com/explore/Popular+Music?tag=out-of-experiment&limit=20&linked_partitioning=1");
if (result != null)
{
var items = Newtonsoft.Json.JsonConvert.DeserializeObject<TrackModel.RootObject> (result);
lst.Adapter = new TrackAdapter(Activity, items.tracks);
}
}
public class TrackAdapter:BaseAdapter
{
LayoutInflater _inflater;
List<TrackModel.Track> _tracks;
public TrackAdapter(Context context, List<TrackModel.Track> tracks)
{
_inflater=LayoutInflater.FromContext(context);
_tracks=tracks;
}
public override TrackModel.Track this[int index]
{
get{ return _tracks [index]; }
}
public override int Count{
get{ return _tracks.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView,ViewGroup parent)
{
View view = convertView ?? _inflater.Inflate (Resource.Layout.ExploreFragment, parent, false);
var track = _tracks [position];
var viewHolder = view.Tag as TrackViewHolder;
if (viewHolder == null) {
viewHolder.Title = view.FindViewById<TextView> (Resource.Id.textviewItems);
viewHolder.SubTitle = view.FindViewById<TextView> (Resource.Id.textviewSubItem);
viewHolder.Image = view.FindViewById<ImageView> (Resource.Id.image);
view.Tag = viewHolder;
}
viewHolder.Title.Text = track.title;
viewHolder.SubTitle.Text = track.track_type;
Android.Net.Uri uri = Android.Net.Uri.Parse (track.artwork_url);
viewHolder.Image.SetImageURI(uri);
return view;
}
}
public class TrackViewHolder:Java.Lang.Object
{
public TextView Title{ get; set;}
public TextView SubTitle{get;set;}
public ImageView Image{ get; set;}
}
public override TrackModel.Track this[int index]. It get a error is makred as an overdie but no suitable indexer found to overide.
I want to take data from json up listview on xamarin android.
If it is unviersal app then it easy to use.
The way you want to set the adapter for your listview will not work that way.
Setting the adapter property of the listview inside the foreach loop is totally wrong. The same applies to your textviews.
You need to implement a custom adapter that loads a layout for each of your track list item. Your custom adapter could look like the following example I've written out of my mind with out further testing. But it implements the required methods a custom adapter needs to implement.
The important part is the GetView method that returns your track layout every time the listview ask for a new item to represent. To keep the app memory down it uses the ViewHolder pattern, which isn't required if you want to use the RecycleView.
public class TrackAdapter : BaseAdapter<Tracks>
{
LayoutInflater _inflater;
List<Tracks> _tracks;
public TrackAdapter(Context context, List<Tracks) tracks)
{
_inflater = LayoutInflater.FromContext(context);
_tracks = tracks;
}
public override Tracks this [int index]
{
get { return _tracks[index]; }
}
public override int Count
{
get { return _tracks.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView ?? _inflater.Inflate(Resource.Layout.TrackListItem, parent, false);
var track = _tracks[position];
var viewHolder = view.Tag as TrackViewHolder;
if (viewHolder == null)
{
viewHolder = new TrackViewHolder();
viewHolder.Title = view.FindViewById<TextView>(Resource.Id.textviewItems);
viewHolder.Subtitle = view.FindViewById<TextView>(Resource.Id.textviewSubItems);
viewHolder.Image = view.FindViewById<ImageView>(Resource.Id.image);
view.Tag = viewHolder;
}
viewHolder.Title.Text = track.title;
viewHolder.SubTitle.Text = track.track_type;
viewHolder.Image.SetImageURI(Uri(track.artwork_url));
return view;
}
class TrackViewHolder : Java.Lang.Object
{
public TextView Title { get; set; }
public TextView SubTitle { get; set; }
public ImageView Image { get; set; }
}
}
The layout will contain your title, subtitle and image and could easily build with a normal layout file.
In your fragment you then create a new instance for TrackAdapter pass the context and the list of tracks you want to be shown in the listview.
public override void OnActivityCreated (Bundle savedInstanceState)
{
base.OnActivityCreated (savedInstanceState);
lst = View.FindViewById<ListView> (Resource.Id.lstHome);
var result = json.GetStringbyJson ("https://api-v2.soundcloud.com/explore/Popular+Music?tag=out-of-experiment&limit=20&linked_partitioning=1");
if (result != null)
{
var items = JsonConvert.DeserializeObject<TrackModel.RootObject> (result);
lst.Adapter = new TrackAdapter(Activity, items.tracks);
}
}
i want to create some highchart widget by Eclipse RAP ,and i follow the official guide like this
handlejs:
var CKEDITOR_BASEPATH = "rwt-resources/";
(function(){
'use strict';
rap.registerTypeHandler( "rap.sunline.HighCharts", {
factory : function( properties ) {
var parent = rap.getObject( properties.parent );
// var element = document.createElement( "div" );
// parent.append( element );
// $(element).html("askldfjaskljdk");
return {};
}
});
}());
widget.java:
public class HightChartComposite extends Composite {
private static final String RESOURCES_PATH = "resources/";
private static final String REGISTER_PATH = "hightcharts/";
private static final String[] RESOURCE_FILES = { "jquery-2.1.0.min.js", "highcharts.js","ChartPaintListener.js" };
private static final String REMOTE_TYPE = "rap.sunline.HightCharts";
private final RemoteObject remoteObject;
private final OperationHandler operationHandler = new AbstractOperationHandler() {
#Override
public void handleSet(JsonObject properties) {
// JsonValue textValue = properties.get("text");
// if (textValue != null) {
// text = textValue.asString();
// }
}
};
public HightChartComposite(Composite parent, int style) {
super(parent, style);
registerResources();
loadJavaScript();
Connection connection = RWT.getUISession().getConnection();
remoteObject = connection.createRemoteObject(REMOTE_TYPE);
remoteObject.setHandler(operationHandler);
remoteObject.set("parent", WidgetUtil.getId(this));
}
private void registerResources() {
ResourceManager resourceManager = RWT.getResourceManager();
boolean isRegistered = resourceManager.isRegistered(REGISTER_PATH + RESOURCE_FILES[0]);
if (!isRegistered) {
try {
for (String fileName : RESOURCE_FILES) {
register(resourceManager, fileName);
}
} catch (IOException ioe) {
throw new IllegalArgumentException("Failed to load resources", ioe);
}
}
}
private void loadJavaScript() {
JavaScriptLoader jsLoader = RWT.getClient().getService(JavaScriptLoader.class);
ResourceManager resourceManager = RWT.getResourceManager();
jsLoader.require(resourceManager.getLocation(REGISTER_PATH + "jquery-2.1.0.min.js"));
jsLoader.require(resourceManager.getLocation(REGISTER_PATH + "highcharts.js"));
jsLoader.require(resourceManager.getLocation(REGISTER_PATH + "ChartPaintListener.js"));
}
private void register(ResourceManager resourceManager, String fileName) throws IOException {
ClassLoader classLoader = HightChartComposite.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(RESOURCES_PATH + fileName);
try {
resourceManager.register(REGISTER_PATH + fileName, inputStream);
} finally {
inputStream.close();
}
}
// //////////////////
// overwrite methods
#Override
public void setLayout(Layout layout) {
throw new UnsupportedOperationException("Cannot change internal layout of CkEditor");
}
}
the error is occur:
Uncaught Error: Operation "create" on target "r6" of type "null" failed:
No Handler for type rap.sunline.HightCharts
Properties:
parent = w5
and i have a question about this , what differents from extends Canvas and Composite;
You forget to implement setters in your javascript code.
The created object is stored by the framework under its object id. This object has to implement setter methods that match the properties defined in the handler, which will then be called when the server sends a set operation for a given property.
since i am not a java swing expert i need some help to understand why my images in my JList do not appear.
I have a JList that pops up containing all products (with inline pictures) while the user enters a search criteria. The results come from lucene and will be rendered in a JList in real time.
To lazy load the inline product images i am using a swingworker inside my rendering class.
Any help would be great!
public abstract class MatchRenderer implements ListCellRenderer {
#Override
public Component getListCellRendererComponent(JList list, final Object value, int index,
boolean isSelected, boolean cellHasFocus) {
Component component = defaultRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (quickRenderMode) {
return component;
} else {
try {
component = renderHook(value, component);
} catch (Exception e) {
System.err.println("Search string: " + searchString);
System.err.println(value.toString());
e.printStackTrace();
}
JPanel itemPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
JLabel label = new JLabel(defaultIcon, SwingConstants.HORIZONTAL);
itemPanel.add(label);
itemPanel.add(component);
if (value instanceof QoogleEntity && ((QoogleEntity) value).isProduct()) {
QoogleEntity qoogleItem = (QoogleEntity) value;
String imageUrl = qoogleItem.getQInfos().get(0).getqValue();
//LAZY LOAD STARTS HERE...
new ImageRetriever(label, imageUrl).execute();
}
return itemPanel;
}
}
protected abstract Component renderHook(Object value, Component component);
class ImageRetriever extends SwingWorker<ImageIcon, String> {
private JLabel lbImage;
private String imageUrl;
public ImageRetriever(JLabel lbImage, String imageUrl) {
this.lbImage = lbImage;
this.imageUrl = imageUrl;
}
#Override
protected void done() {
try {
lbImage.setIcon(get());
lbImage.repaint();
} catch (Exception e) {
}
}
#Override
protected ImageIcon doInBackground() throws Exception {
return ImageLoader.loadImageFromUrl(imageUrl, 80, 80);
}
};
I have added a document listener to a JTextPane. I want to know what text has been added or removed so I can take action if certain key words are entered. The insert part works just fine, but I do not know how to detect what text was deleted.
The insert works because the text is there and I can select it, but the delete has already removed the text so I get bad location exceptions sometimes.
I want to make reserved words that are not inside quotes bold so I need to know what has been removed, removing even one character (like a quote) could have a huge impact.
My code follows:
#Override
public void insertUpdate(DocumentEvent e)
{
Document doc = e.getDocument();
String i = "";
try
{
i = doc.getText(e.getOffset(), e.getLength());
}
catch(BadLocationException e1)
{
e1.printStackTrace();
}
System.out.println("INSERT:" + e + ":" + i);
}
#Override
public void removeUpdate(DocumentEvent e)
{
Document doc = e.getDocument();
String i = "";
try
{
i = doc.getText(e.getOffset(), e.getLength());
}
catch(BadLocationException e1)
{
e1.printStackTrace();
}
System.out.println("REMOVE:" + e + ":" + i);
}
This is strange that there is no simple way to get this information.
I've looked at the source code of Swing libraries for this. Of course - there is this information in DocumentEvent, which is of class AbstractDocument$DefaultDocumentEvent, which contains protected Vector<UndoableEdit> edits, which contains one element of type GapContent$RemoveUndo, which contains protected String string that is used only in this class (no other "package" classes get this) and this RemoveUndo class have no getter for this field.
Even toString didn't show it (because RemoveUndo hasn't overrided toString method):
[javax.swing.text.GapContent$RemoveUndo#6303ddfd hasBeenDone: true alive: true]
This is so strange for me that I belive that there is some other easy way to get the removed string and that I just don't know how to accomplish it.
One thing you can do is the most obvious:
final JTextArea textArea = new JTextArea();
textArea.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
previousText = textArea.getText();
}
});
textArea.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void removeUpdate(DocumentEvent e) {
if(previousText != null) {
String removedStr = previousText.substring(e.getOffset(), e.getOffset() + e.getLength());
System.out.println(removedStr);
}
}
#Override
public void insertUpdate(DocumentEvent e) {
}
#Override
public void changedUpdate(DocumentEvent e) {
}
});
where previousText is an instance variable.
or (the most nasty ever):
textArea.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void removeUpdate(DocumentEvent e) {
String removedString = getRemovedString(e);
System.out.println(removedString);
}
#Override
public void insertUpdate(DocumentEvent e) {
}
#Override
public void changedUpdate(DocumentEvent e) {
}
});
plus this method:
public static String getRemovedString(DocumentEvent e) {
try {
Field editsField = null;
Field[] fields = CompoundEdit.class.getDeclaredFields();
for(Field f : fields) {
if(f.getName().equals("edits")) {
editsField = f;
break;
}
}
editsField.setAccessible(true);
List edits = (List) editsField.get(e);
if(edits.size() != 1) {
return null;
}
Class<?> removeUndo = null;
for(Class<?> c : GapContent.class.getDeclaredClasses()) {
if(c.getSimpleName().equals("RemoveUndo")) {
removeUndo = c;
break;
}
}
Object removeUndoInstance = edits.get(0);
fields = removeUndo.getDeclaredFields();
Field stringField = null;
for(Field f : fields) {
if(f.getName().equals("string")) {
stringField = f;
break;
}
}
stringField.setAccessible(true);
return (String) stringField.get(removeUndoInstance);
}
catch(SecurityException e1) {
e1.printStackTrace();
}
catch(IllegalArgumentException e1) {
e1.printStackTrace();
}
catch(IllegalAccessException e1) {
e1.printStackTrace();
}
return null;
}
I had the same problem than you. And what Xeon explained help me a lot too. But after, i found a way to do that. In my case, i created a custom StyledDocument class that extends DefaultStyledDocument:
public class CustomStyledDocument extends DefaultStyledDocument
{
public CustomStyledDocument () {
super();
}
#Override
public void insertString(int offset, String string, AttributeSet as) throws BadLocationException {
super.insertString(offset, string, as);
}
#Override
public void remove(int offset, int i1) throws BadLocationException {
String previousText = getText(offset, i1);
super.remove(offset, i1);
}
}
So if you call getText method before you call super.remove(...), you will get the previous text.