Thursday, September 15, 2011

A closer look into Listview

This is about understanding listviews.

There are a few component to a listview in Android

1. The view
2. The arrayadapter
3. The data
4. The listener
5. A customised look

Standard declaration:
//base listview
Listview lview = (ListView) findViewById(R.id.AlistViewInXML);
lview.setAdapter(aAdapt);

//data-binding
We can use objects in binding data - since we can define objects - we can define values individually. We can also use ArrayList to house multiple objects.

For example, a object with three values - obj.V1, obj.V2 and obj.V3 each representing different values.

//customised look
We can design a view to be house into a item in a ListView. For instance, we can have 1 single layout view housing 3 separate textviews - tv1, tv2, tv3.


//declare new arrayadapter for our listview
// this arrayadapter will house 1. The data and the listener. But we can't use the standard listview if we wish to customise the listview. Thus, we will need to overload this standard call:

ArrayAdapter aAdapt = new ArrayAdapter (context, ViewToShowAsASingleItem, Data){


@Override
public View getView(int position, View cv, ViewGroup parent){
//arrange your ListView appearance
View rw = cv; //This is the view per item
buildAHolder hold;

if(rw == null){
//Set item appearance - when null, the item is recycled
LayoutInflater inflater=getLayoutInflater();
hold = new buildAHolder();
//with a holder - we can do referencing
hold.H_A = (TextView)((View) rw).findViewById(R.id.tv1);
hold.H_B = (TextView)((View) rw).findViewById(R.id.tv2);
hold.H_C = (TextView)((View) rw).findViewById(R.id.tv3);
//Use Tag to hold the holder class for retrieval subsequently
rw.setTag(hold);
hold.H_A.setTag(position);
} else {
// Get the ViewHolder back to get fast access to the TextViews
hold = (buildAHolder) rw.getTag();
hold.H_A.setTag(position);
}//End row recycling
//Set Data items to views
hold.H_A .setText(super.getItem(position).V1.toString());
hold.H_B .setText(super.getItem(position).V2.toString());
hold.H_C .setText(super.getItem(position).V3.toString());

cv.setOnClickListener(CustomclickListener); //you can choose where to put this
return cv;
} //End getView
OnClickListener CustomclickListener = new OnClickListener(){
public void onClick(View v) {
//Actions on click
}
}; //End onclicklistener
class buildAHolder{
//house views
TextView H_A; TextView H_B; TextView H_C;
}//End class

}; //End aAdapt

That's it about ListView - adapters
Notice also that we can do references with objects

1. Setup method to store and return View in an object. eg - setView and getView.
2. With setView, we can then set the preferred Layout into the object
3. Then use getView within the arrayadapter to extract the relevant view

Example:
View SelectedView;
if(a==true){SelectedView = (Layout) findViewById(R.Layout.Layout1;}
else{SelectedView = (Layout) findViewById(R.Layout.Layout2;}

obj.get(0).setView = SelectedView;

//In arrayadapater overloading
ArrayAdapter aAdapt = new ArrayAdapter (context, 1, Data){
public View getView(int position, View cv, ViewGroup parent){
if (position==0){//only reference view once first position
cv = obj.get(0)getView; // Note how normal textviewresourceid is any value (1 here)
}
View row = cv;

.... rest of code
}

}




Friday, August 26, 2011

Gradients -- A deeper look


There is a setShader function within drawables. The following simplify coloring of a drawable object:

ShapeDrawable aDrawable = new ShapeDrawable(new OvalShape());
LinearGradient AGradient = new LinearGradient(x, y, x1, y1, LeftTopColor, RightbottomColor, Shader.TileMode.CLAMP);
aDrawable.getPaint().setShader(AGradient);

The result of simple manipulation on x, y, x1, y1



coding -
Butn 1 - new LinearGradient(0, 0, 50, 0, ColorYellow, ColorRed, Shader.TileMode.CLAMP);
Butn 2 - new LinearGradient(0, 0, 0, 50, ColorYellow, ColorRed, Shader.TileMode.CLAMP);
Butn 3 - new LinearGradient(50, 0, 0, 0, ColorYellow, ColorRed, Shader.TileMode.CLAMP);
Butn 4 - new LinearGradient(0, 50, 0, 0, ColorYellow, ColorRed, Shader.TileMode.CLAMP);




With the absence of either x or y, we have a gradient from x to y (Either top to bottom or right to left). With x and y (as below), we will have a gradient from top-left to bottom-right or top-right to bottom-left.

My belief is that x,y forms the coordinates for color1 and x1,y1 forms the coordinates for color2.
The distance between x1,y1 and x,y determines the direction of the gradient and angle.

shifting the numbers slightly
Butn 1 - new LinearGradient(0, 0, 50, 50, ColorYellow, ColorRed, Shader.TileMode.CLAMP);
Butn 2 - new LinearGradient(0, 0, 100, 100, ColorYellow, ColorRed, Shader.TileMode.CLAMP);
Butn 3 - new LinearGradient(50, 50, 0, 0,ColorYellow, ColorRed, Shader.TileMode.CLAMP);
Butn 4 - new LinearGradient(100, 100, 0, 0, ColorYellow, ColorRed, Shader.TileMode.CLAMP);

result:




Butn 1 - new LinearGradient(50, 50, 50, 0, ColorYellow, ColorRed, Shader.TileMode.CLAMP);
Butn 2 - new LinearGradient(0, 50, 50, 0, ColorYellow, ColorRed, Shader.TileMode.CLAMP);
Butn 3 - new LinearGradient(50, 0, 50, 0,ColorYellow, ColorRed, Shader.TileMode.CLAMP);
Butn 4 - new LinearGradient(0, 0,50, 0, ColorYellow, ColorRed, Shader.TileMode.CLAMP);


Saturday, August 20, 2011

State List Drawables

It takes a long time to figure this out by referring to documentation

The objective is to make a customizable button that reacts to user-touch input

In android, there are many states to a View in any particular time. State List Drawables can be used to control the appearance of the View in reaction to the particular state.

In this example i will have two buttons, each having a single statelistdrawable and a onClickListener that will change the other's state.


--------------------------- A statelistdrawable subclass --------------------------------

public class ImDraw extends StateListDrawable {
int alphaValue; int heightValue; int widthValue;
Canvas canvasIM;
ColorFilter cFilter;
StateListDrawable ImSLDrawable;
Drawable ImDrawable; Drawable ImDrawable1; Drawable ImDrawable2;
Paint paintIM;
int xHeight; int xWidth;
int currentType;
public ImDraw(int drawType, int intHeight, int intWidth){
//Set default values on start
alphaValue = 255;
cFilter = new ColorFilter();
currentType = drawType; xHeight = intHeight; xWidth = intWidth;
}
public StateListDrawable getSLD(){
//Set drawables colors
int drawColor1 = Color.argb(alphaValue, 255, 0, 0); //Paint Red
int drawColor2 = Color.argb(alphaValue, 255, 255, 0); //Paint Yellow
int drawColor3 = Color.argb(alphaValue, 255, 255, 255); //Paint White

//Draw desired drawables for the states - note the sub-class of normalSingleDrawables
normalSingleDrawables nSDA = new normalSingleDrawables(1, xHeight, xWidth, drawColor1, alphaValue);
normalSingleDrawables nSDB = new normalSingleDrawables(1, xHeight, xWidth, drawColor2, alphaValue);
normalSingleDrawables nSDC = new normalSingleDrawables(1, xHeight, xWidth, drawColor3, alphaValue);
ImSLDrawable = new StateListDrawable();
//Setup states to android.attr state
// int stateChecked = android.R.attr.state_checked;
int stateFocused = android.R.attr.state_focused;
int statePressed = android.R.attr.state_pressed;
int stateSelected = android.R.attr.state_selected;
//Set states --- notice 15 is setup as an additional, outside android.attr state
ImSLDrawable.addState(new int[] {15}, nSDC);
ImSLDrawable.addState(new int[] {statePressed}, nSDA);
ImSLDrawable.addState(new int[] {stateSelected}, nSDA);
ImSLDrawable.addState(new int[] {stateFocused}, nSDA);
ImSLDrawable.addState(new int[] {-stateFocused, -statePressed, -stateSelected}, nSDB);
return ImSLDrawable;

}
// ----- Start sub-class
class normalSingleDrawables extends Drawable{
int alphaValue;
int xPos = 1 ;int yPos = 1;
int xWidth; int yHeight;
int paintcolor;

public normalSingleDrawables(int choice, int intHeight, int intWidth, int dPaint, int alpha) {
xWidth = intWidth; yHeight = intHeight;
paintcolor = dPaint;
alphaValue = alpha;

//set the shape of drawable based on values

switch (choice) {
case 1: //Draw a rectangle
ImDrawable = new ShapeDrawable(new RectShape());
break;
case 2: //Draw a circle
ImDrawable = new ShapeDrawable(new OvalShape());
break;
default: //Draw a rectangle
ImDrawable = new ShapeDrawable(new RectShape());
} }

public void draw(Canvas canvasIM) {
((ShapeDrawable) ImDrawable).getPaint().setColor(paintcolor);
ImDrawable.setBounds(xPos, yPos, xPos + xWidth ,yPos + yHeight);
ImDrawable.draw(canvasIM); }

@Override
public int getOpacity() {
return PixelFormat.OPAQUE; }

@Override
public void setAlpha(int newAlphaValue) {
alphaValue = newAlphaValue; }

@Override
public void setColorFilter(ColorFilter cf) {
cf = cFilter; }
}

// ----- End sub-class
}

--------------------------- A statelistdrawable subclass --------------------------------
------------------------ On Application main activity --------------------------------
public class MYIM extends Activity {
//Default
TextView mainTextView;
String Msg = "";
Button mainButton = null; Button SideButton = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
//default activity code
super.onCreate(savedInstanceState);
//reference main.xml as User Interface
setContentView(R.layout.main);
//Set references point to our main.xml file - there must be two buttons with id -btnMain and btnSide
mainButton = (Button) findViewById(R.id.btnMain);
SideButton = (Button) findViewById(R.id.btnSide);
//Create our custom SLD
//Set drawables for our buttons
ImDraw NewIM = new ImDraw(1,
mainButton.getLayoutParams().height, mainButton.getLayoutParams().width);
mainButton.setBackgroundDrawable(NewIM.getSLD());

NewIM = new ImDraw(1,
SideButton.getLayoutParams().height, SideButton.getLayoutParams().width);
SideButton.setBackgroundDrawable(NewIM.getSLD());

//Set onClick for our buttons
mainButton.setOnClickListener(new OnClickListener(){
public void onClick(View view){
//Switch the other button to State No 15!
SideButton.getBackground().setState(new int[]{15});
}
});
SideButton.setOnClickListener(new OnClickListener(){
public void onClick(View view){
//Switch the other button to State No 15!
mainButton.getBackground().setState(new int[]{15});
}
});

}
}