KetaiList

edited March 2018 in Android Mode

Hi. I copied the KetaiList class into a new processing tab to be able to customize it. But I only managed to change the backGround color. I tried to set textColor and do some padding, but although it doesn't give any errors, it also hasn't any effect. Any idea what is wrong? Thanks in advance

import java.lang.reflect.Method;
import java.util.ArrayList; 
import processing.core.PApplet;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView; 

// void onKetaiListSelection(String selection) - selection is the string * selected from the list

public class KetaiList extends ListView { 

  private PApplet parent; 
  private ArrayAdapter<String> adapter; 
  String name = "KetaiList"; 
  String selection = "";
  ListView self; 
  RelativeLayout layout; 
  private Method parentCallback; 
  String title = "";
  public KetaiList(PApplet _parent, ArrayList<String> data) {       
    super(_parent.getActivity().getApplicationContext());       
    parent = _parent;       
    adapter = new ArrayAdapter<String>(parent.getActivity(), android.R.layout.simple_list_item_1, data);        
    init();
  } 
  public KetaiList(PApplet _parent, String[] data) {        
    super(_parent.getActivity().getApplicationContext());       
    parent = _parent;       
    adapter = new ArrayAdapter<String>(parent.getActivity(), android.R.layout.simple_list_item_1, data);        
    init();
  }
  public KetaiList(PApplet _parent, String _title, String[] data) {     
    super(_parent.getActivity().getApplicationContext());       
    parent = _parent;       
    title = _title;     
    adapter = new ArrayAdapter<String>(parent.getActivity(), android.R.layout.simple_list_item_1, data);        
    init();
  } 
  public KetaiList(PApplet _parent, String _title, ArrayList<String> data) {        
    super(_parent.getActivity().getApplicationContext());       
    parent = _parent;       
    title = _title;     
    adapter = new ArrayAdapter<String>(parent.getActivity(), android.R.layout.simple_list_item_1, data);        
    init();
  } 
  public void refresh() {       
    if (adapter == null)            return;     
    parent.getActivity().runOnUiThread(new Runnable() {         
      public void run() {               
        adapter.notifyDataSetChanged();
      }
    }
    );
  } 
  public String getSelection() {        
    return selection;
  }
  private void init() {     
    setBackgroundColor(Color.BLUE);     
  //  setTextColor(Color.BLACK);
    setAlpha(1);        
    self = this;        
    layout = new RelativeLayout(parent.getActivity());      

    if (title != "") {          
      TextView tv = new TextView(parent.getActivity());
   //   tv.setPadding(100,100,0,0);
      tv.setText(title);            
   //   tv.setTextColor(Color.parseColor("#bdbdbd"));
      setHeaderDividersEnabled(true);           
      addHeaderView(tv);
    }       
    try {           
      parentCallback = parent.getClass().getMethod("onKetaiListSelection", new Class[] { KetaiList.class });            
      PApplet.println("Found onKetaiListSelection...");
    } 
    catch (NoSuchMethodException e) {
    }       
    setAdapter(adapter);        
    setOnItemClickListener(new OnItemClickListener() {          
      public void onItemClick(AdapterView<?> p, View view, int position, long id) {                 
        selection = adapter.getItem(position).toString();               
        layout.removeAllViewsInLayout();                
        try {                   
          parentCallback.invoke(parent, new Object[] { self });
        } 
        catch (Exception ex) {
        }               
        self.setVisibility(View.GONE);              
        ((ViewManager) self.getParent()).removeView(self);              
        parent.getActivity().runOnUiThread(new Runnable() {                 
          public void run() {                       
            layout.removeAllViews();                        
            layout.setVisibility(View.GONE);
          }
        }
        );
      }
    }
    ); 
    parent.getActivity().runOnUiThread(new Runnable() {         
      @ SuppressWarnings("deprecation")     
        public void run() {             
        parent.getActivity().addContentView(self, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
      }
    }
    );
  }
}

Answers

  • why start another question when there's one with half a dozen replies already?

  • I am sorry, I searched again, but I can't find any topic about customizing the KetaiList Class or setting parameters of textView programmatically on this forum. I do find it on Java sites, but I couldn't get it working.

  • Are you referring to line 66?

    Notice the ketai list is working with a ListView object, which is a widget provided by the Android API. You need to get the element and changed its properties.

    Kf

  • but I can't find any topic about customizing the KetaiList Class

    i meant your other question:

    https://forum.processing.org/two/discussion/26878/converting-file-to-arraylist

    https://forum.processing.org/two/discussion/26859/file-list-files-in-directory

    3 questions for the same bit of code...

  • edited March 2018

    @kfrajer Hi. I'm not sure what you mean by element. It all starts with the PApplet Class and, I know .that Processing's functions are included as methods in this class. I didn't have the courage to look into that Class. I'm just scratching the Java borders. But I assume that it has a linear layout and that the in the KetaiList relative layout is attached to it as a child. Also l don't know what 'this' refers to, at line 68, when the ListView is initialized. Then a TextView is added. Why? I didn't see that in Java examples. I tried to change these in line 73 and 75, but doesn't work. Most of Java examples use XML method so this makes it harder to understand.

  • edited March 2018

    I copied the KetaiList class into a new processing tab to be able to customize it.

    You're much better off by simply making your own customized class which extends KetaiList instead, inside a ".java" tab: ~O)
    https://Processing.org/reference/extends.html

    "KList.java":

    package ketai.ui;
    
    import ketai.ui.KetaiList;
    
    public class KList extends KetaiList {
      // ...
    }
    

    Then use @Override only on those methods you wish to customize.

    You can also use super in order to invoke the original method, either before or after your modifications. :-bd

  • edited March 2018

    Also l don't know what this refers to, at line 68, when the ListView is initialized.

    Java's keyword this refers to the current instance of the class which it has been typed into. ~O)

    Line #68 is inside class KetaiList. Therefore this is of datatype KetaiList. :-B

    https://Processing.org/reference/this.html

  • edited March 2018 Answer ✓

    Currently, most of the job is done in the init() function. If you want to change something, you are better off writing your own class where you define your own changes before the list is displayed.

    What kind of padding do you want to add? You mentioned about changing text and background color... anything else?

    For changes in the ListView, consult: https://developer.android.com/reference/android/widget/ListView.html

    Ketai is a library that allows you to easily use objects and functionalities provided by the Android API. It is doing all the heavy work for you at a cost of less flexibility aka. no customization. For anybody that wants to modify the ketai list demo, they are better off to write it from scratch by adding an extra layout to customize its objects. For instance, the text color of the list could be different than the text color of the title.

    More on the technical side: The library's init() and the adapter object are private members, which means they cannot be accessed (easily). For the amount of code it saves you there and the effort to introduce changes, you are better off doing it on your own, exactly what you are doing above (Yes, extending the class would not work). I will create a ticket in ketai requesting making those items public but it will not give you the flexibility you are looking for in the long run as the current layout of the code wouldnt allow use to reuse their code. Below is my demo demonstrating one of the changes you are looking for.

    Kf

    //REFERENCES: https:// stackoverflow.com/questions/4533440/android-listview-text-color
        //REFERENCES: https:// stackoverflow.com/questions/3663745/what-is-android-r-layout-simple-list-item-1
        //REFERENCES: https:// developer.android.com/reference/android/widget/ArrayAdapter.html
        //REFERENCES: https:// github.com/ketai/ketai/blob/master/src/ketai/ui/KetaiList.java
        //REFERENCES: http:// ketai.org/examples/ui/
    
    //INSTRUCTIONS:
    //         *--  You get two different lists in this sketch.
    //         *--  Ok, the list are the same but they have different
    //         *--  text color. Tapping on the upper half of the sketch
    //         *--  makes the text color blue. Otherwise, it uses the 
    //         *--  custom defined color.
    
    //===========================================================================
    // IMPORTS:
    
    import android.app.Activity;
    import android.content.Context;
    import android.widget.FrameLayout;
    //import android.app.Fragment;
    
    import android.os.Environment;
    import android.graphics.Color;
    import android.widget.Toast;
    import android.os.Looper;
    import android.view.WindowManager;
    import android.os.Bundle;
    import android.view.ViewParent;
    import android.view.ViewGroup;
    import android.view.View;
    import android.widget.RelativeLayout;
    import android.view.LayoutInflater;
    import android.R.string;
    
    
    //===========================================================================
    // FINAL FIELDS:
    
    
    //===========================================================================
    // GLOBAL VARIABLES:
    
    Activity act;
    Context mC;
    
    SelectionKList selectionlist;
    ArrayList<String> colorlist; 
    color currentColor;
    
    //===========================================================================
    // PROCESSING DEFAULT FUNCTIONS:
    
    void setup() {
      //size(400,600);
      fullScreen();
      orientation(PORTRAIT);
      //orientation(LANDSCAPE;)
    
      act = this.getActivity();
      Looper.prepare();
    
      textAlign(CENTER, CENTER);
      rectMode(CENTER);
    
      fill(255);
      strokeWeight(2);
      textSize(32);
    
      currentColor=color(0);
    
      colorlist = new ArrayList<String>();
      colorlist.add("Black");
      colorlist.add("Red");
      colorlist.add("Green");
      colorlist.add("Blue");
      colorlist.add("Gray");
      for (int i = 0; i < 20; i++)
        colorlist.add("Stub Entry " + i);
    }
    
    void draw() {
      background(currentColor);
    }
    
    void keyReleased() {
    }
    
    void mouseReleased() {
    
      if (mouseY>height/2)
        selectionlist = new SelectionKList(this, colorlist);
      else
        selectionlist = new SelectionKList(this, "Hello World", colorlist);
    }
    
    
    //===========================================================================
    // OTHER FUNCTIONS:
    
    void onSelectionKListSelection(SelectionKList klist)
    {
      String selection = klist.getSelection();
      if (selection == "Black")
        currentColor = color(0, 0, 0);
      else if (selection == "Red")
        currentColor = color(255, 0, 0);
      else if (selection == "Green")
        currentColor = color(0, 255, 0);
      else if (selection == "Blue")
        currentColor = color(0, 0, 255);
      else if (selection == "Gray")
        currentColor = color(128, 128, 128);
    }
    
    
    
    //===========================================================================
    // ANDROID ACTIVITY LIFECYCLE'S FUNCTIONS:
    
    
    
    //  @@@@@@@@@@@@
    @ Override 
      public void onResume() {
      super.onResume();
    
      act = this.getActivity();
      mC= act.getApplicationContext();
    
    }
    
    /**
     * 
     */
    
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    
    import processing.core.PApplet;
    import android.graphics.Color;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.ViewManager;
    import android.widget.AdapterView;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    
    /**
     * The SelectionKList class provides an android UI scroll list. To receive the
     * selection data a sketch should define the following method:<br />
     * <br />
     * 
     * void onSelectionKListSelection(String selection) - selection is the string
     * selected from the list<br />
     */
    public class SelectionKList extends ListView {
    
      /** The parent. */
      private PApplet parent;
    
      /** The adapter. */
      public ArrayAdapter<String> adapter;
    
      /** The name. */
      String name = "SelectionKList";
    
      /** The selection. */
      String selection = "";
    
      /** The self. */
      ListView self;
    
      /** The layout. */
      RelativeLayout layout;
    
      /** The parent callback. */
      private Method parentCallback;
    
      /** The title. */
      String title = "";
    
      /**
       * Instantiates a new ketai list.
       *
       * @param _parent
       *            the _parent
       * @param data
       *            the data
       */
      public SelectionKList(PApplet _parent, ArrayList<String> data) {
        super(_parent.getActivity().getApplicationContext());
        parent = _parent;
        adapter = new ArrayAdapter<String>(parent.getActivity(), android.R.layout.simple_list_item_1, data);
        init();
      }
    
      /**
       * Instantiates a new ketai list.
       *
       * @param _parent
       *            the _parent
       * @param data
       *            the data
       */
      public SelectionKList(PApplet _parent, String[] data) {
        super(_parent.getActivity().getApplicationContext());
    
        parent = _parent;
        adapter = new ArrayAdapter<String>(parent.getActivity(), android.R.layout.simple_list_item_1, data);
        init();
      }
    
      /**
       * Instantiates a new ketai list.
       *
       * @param _parent
       *            the _parent
       * @param _title
       *            the _title
       * @param data
       *            the data
       */
      public SelectionKList(PApplet _parent, String _title, String[] data) {
        super(_parent.getActivity().getApplicationContext());
    
        parent = _parent;
        title = _title;
        adapter = new ArrayAdapter<String>(parent.getActivity(), android.R.layout.simple_list_item_1, data);
        init();
      }
    
      /**
       * Instantiates a new ketai list.
       *
       * @param _parent
       *            the _parent
       * @param _title
       *            the _title
       * @param data
       *            the data
       */
      public SelectionKList(PApplet _parent, String _title, ArrayList<String> data) {
        super(_parent.getActivity().getApplicationContext());
        parent = _parent;
        title = _title;
        adapter = new ArrayAdapter<String>(parent.getActivity(), android.R.layout.simple_list_item_1, data) {
          @Override
            public View getView(int position, View convertView, ViewGroup parent) {
            View view =super.getView(position, convertView, parent);
    
            TextView textView=(TextView) view.findViewById(android.R.id.text1);
    
            /**YOUR CHOICE OF COLOR*/
            textView.setTextColor(Color.BLUE);
    
            return view;
          }
        };
        init();
      }
    
      /**
       * Refresh.
       */
      public void refresh() {
        if (adapter == null)
          return;
        parent.getActivity().runOnUiThread(new Runnable() {
          public void run() {
            adapter.notifyDataSetChanged();
          }
        }
        );
      }
    
      /**
       * Gets the selection.
       *
       * @return the selection
       */
      public String getSelection() {
        return selection;
      }
    
      /**
       * Inits the.
       */
      public void init() {
        setBackgroundColor(Color.LTGRAY);
        setAlpha(1);
        self = this;
    
        layout = new RelativeLayout(parent.getActivity());
        SetTitleIfAny();
        setAdapter(adapter);
    
        setOnItemClickListener(new OnItemClickListener() {
          public void onItemClick(AdapterView<?> p, View view, int position, long id) {
    
            selection = adapter.getItem(int(id)).toString();
    
            layout.removeAllViewsInLayout();
            try {
              parentCallback.invoke(parent, new Object[] { self });
            } 
            catch (Exception ex) {
            }
    
            self.setVisibility(View.GONE);
            ((ViewManager) self.getParent()).removeView(self);
            parent.getActivity().runOnUiThread(new Runnable() {
              public void run() {
                layout.removeAllViews();
                layout.setVisibility(View.GONE);
              }
            }
            );
          }
        }
        );
    
        try {
          parentCallback = parent.getClass().getMethod("onSelectionKListSelection", new Class[] { SelectionKList.class });
          PApplet.println("Found onSelectionKListSelection...");
        } 
        catch (NoSuchMethodException e) {
        }
    
    
        addToMainView();
      }
    
      /**
       * Adds title if not empty
       */
      void SetTitleIfAny() {
        if (title != "") {
          TextView tv = new TextView(parent.getActivity());
          tv.setText(title);
          setHeaderDividersEnabled(true);
          addHeaderView(tv);
        }
      }
    
      /**
       * Add to the main view...
       */
      void addToMainView() {
        parent.getActivity().runOnUiThread(new Runnable() {
          @SuppressWarnings("deprecation")
            public void run() {
            parent.getActivity().addContentView(self, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, 
              ViewGroup.LayoutParams.FILL_PARENT));
          }
        }
        );
      }
    }
    
  • edited March 2018

    I will create a ticket in ke:tai requesting making those items public.

    Actually folks should stop declaring class members as private (nor leave them as default access-level either) for Processing's 3d-party libraries for good! [-(

    A much better choice is protected. *-:)
    It hides a member for regular library usage. But leave it open for subclassing customization. \m/

  • @GoToLoop Yes, protected is better. A request already exists in the repo.

    Kf

  • @kfrajer Thank you so much for your effort with all the comments. Now I will try to understand as much as possible, and do some more customization.

  • @kfrajer I can change the parameters like ViewGroup.LayoutParams(3 * width / 4 , 3 * height / 4)); But I would like to use .setMargins(left, top, right , bottom); Once again thanks for the code above I' m capable of customizing a lot of things now.

  • Answer ✓

    Not sure about margins, but you should explore

    https://developer.android.com/reference/android/view/ViewGroup.LayoutParams.html

    This is in

    parent.getActivity().addContentView(self, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, 
              ViewGroup.LayoutParams.FILL_PARENT));
    

    You can adjust the width and the height there. Then you should be able to call setX and setY, functions associated to the ListView list. No time to test right now, hopefully it gives you a lead of what to do.

    Kf

    self.setY(500);
    parent.getActivity().addContentView(self, new ViewGroup.LayoutParams(width/2,height/2);
    
  • edited March 2018

    @kfrajer Yes, ofcourse, it is related to 'self'. Now with code below you can set the parameters. I'm slowly getting grip on this stuff. Thanks!

    ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) self.getLayoutParams();
     layoutParams.setMargins(150, 150, 150, 150);
    
  • edited March 2018

    @kfrajer The only two parameters left to be set would be the color and height of the divider line using .setDivider(#cceebb); .setDividerHeight(1); But it always gives me the error:

    The method setDivider(Drawable) in the type ListView is not applicable for the arguments (int)

  • Setting the dividerHeight is easy using self.setDividerHeight(5); in the addToMainView function, but setting the divider color is more difficult because it's parameter has to be a drawable. I've tried code like

    color sage = color(#cceebb);
    ColorDrawable sage = new ColorDrawable(this.getResources().getColor(sage)); 
    self.setDivider(new ColorDrawable(Color.parseColor(sage))); 
    

    But it already starts with the out of many errors

    ColorDrawable cannot be resolved to a type

Sign In or Register to comment.