Android- Multiple Views not being displayed.(Only first view displays) - android

I have searched a great deal and have not found a solution to my problem. When I create multiple views and try to add them to a LinearLayout only the first view (cake) displays.
Here is where I create and add the views.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.image_View);
PlayAreaView cake = new PlayAreaView(SecondTestActivity.this, R.drawable.cake);
views.add(cake);
PlayAreaView bomb = new PlayAreaView(SecondTestActivity.this, R.drawable.bomb);
views.add(bomb);
PlayAreaView crown = new PlayAreaView(SecondTestActivity.this, R.drawable.crown);
views.add(crown);
PlayAreaView scissors = new PlayAreaView(SecondTestActivity.this, R.drawable.cut);
views.add(scissors);
PlayAreaView trash = new PlayAreaView(SecondTestActivity.this, R.drawable.bin_closed);
views.add(trash);
PlayAreaView key = new PlayAreaView(SecondTestActivity.this, R.drawable.bullet_key);
views.add(key);
LayoutParams params
= new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
for(View v : views){
Log.v("created", "view created");
v.setLayoutParams(params);
linearLayout.addView(v);
}
}
Here is my main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/main_View"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="#+id/image_View"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
</LinearLayout>
</FrameLayout>
I can create a single view and be fine but I am unable to add multiple views the the LinearLayout. Why is this?

If you look here, there was another person with basically the same problem. However, they were not declaring the orientation of their layout so it defaulted to horizontal. In your layout you have explicitly declared horizontal. Is this intended (for example to have the items show up side-by-side)? If not, change the orientation to vertical and you should be good.
If you need them to show side-by-side, then I am not sure off the top of my head how to do that, but I would guess you need to declare each view as next to the view placed before it (e.g. using something like 'alignToRightOf'. Again, this is just a stab-in-the-dark but it may get you going on a correct path.
Hope this helps.

I found the answer to my problem. I did not fully understand how the Activity handled views. For me to draw multiple separate views I have to loop over each view that I add to an array and call an overridden draw method in the custom view. After I understood this I was able to create multiple views and add separate dragging functions on each view. Here's the code.
public class ThirdTestActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout layout = (LinearLayout) findViewById(R.id.main_View);
layout.addView(new MyCircles(this));
}
private class MyCircles extends View{
private Context myContext;
private ArrayList<MyCircle> circles = new ArrayList<MyCircle>();
private int size = 10;
public MyCircles(Context context) {
super(context);
myContext = context;
addCircles();
}
private void addCircles(){
for (int i = 0; i < size; i++){
circles.add(new MyCircle(myContext, R.drawable.skullcrossbones, i * 40, 50));
}
}
#Override
protected void onDraw(Canvas canvas){
for (View v : circles){
v.draw(canvas);
}
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
int mouseX = (int)event.getX();
int mouseY = (int)event.getY();
MyCircle image = null;
for(MyCircle images : circles){
//Log.v("image checked X: " + images.imageX + ", Y: " + images.imageY, "checked");
// Is the event inside of this view?
if(images.getImageRect().contains((int)event.getX(), (int)event.getY()))
{
image = images;
}
}
if (image != null){
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
Log.v("touched down", "touched down at X: " + mouseX + ", Y: " + mouseY);
image.dragDistance = new Point(mouseX, mouseY);
bringToFront();
isSelected();
return true;
}
else if(event.getAction() == MotionEvent.ACTION_MOVE)
{
Log.v("move", "moving to X: " + mouseX + ", Y: " + mouseY);
image.dragDistance.set(mouseX, mouseY);
invalidate();
return true;
}
}
return super.onTouchEvent(event);
}
}
private class MyCircle extends View{
private int imageId;
private Drawable image;
private Context myContext;
private int size = 48;
private int imageOffset = size/2;
private int imageX;
private int imageY;
private Point dragDistance;
public MyCircle(Context context, int id, int x, int y) {
super(context);
myContext = context;
imageId = id;
imageX = x;
imageY = y;
dragDistance = new Point(imageX + imageOffset, imageY + imageOffset);
}
public Rect getImageRect(){
return image.getBounds();
}
#Override
public void draw(Canvas canvas) {
//Log.v("draw","drawn");
super.onDraw(canvas);
image = myContext.getResources().getDrawable(imageId);
imageX = (dragDistance.x - imageOffset);
imageY = (dragDistance.y - imageOffset);
image.setBounds(imageX, imageY, imageX + size, imageY + size);
image.draw(canvas);
}
}
}
This is written for Android version 2.1 API 7

Related

[Android]onTouch in child View is not responding

I have been working on making Sudoku grid whose cell's value changes whenever I touch on a cell. So I have implemented this sudoku grid in a LinearLayout by Child View, and tried using OnTouch method, but it is not working. I tried using log method to check whether onTouch is actually called, but it seemes that this method is perfectly ignored. I have been searching for solutions on other question, but it seems none of those solutions helped. I feel kinda suck here, and any help would be greatly appreciated.
Here is my code:
SudokuActivity.java
package snacker.nonogramsolver;
import ...; /*many things are imported here*/
public class SudokuActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sudoku);
Button btn = (Button)findViewById(R.id.btn_clear);
Sudoku sdk = new Sudoku(this);
sdk.setOnTouchListener(sdk);
}
}
;
Sudoku.java
package snacker.nonogramsolver;
import ...;
public class Sudoku extends View implements View.OnTouchListener {
int mWidth = 9;
int mHeight = 9;
int mCellWidth, mCellHeight;
int mCellMargin;
int mEdgeThick;
int mStatus;
int mTextSize;
int mXNow = -1, mYNow = -1;
int[][] mBoard = new int[9][9];
Point mBoardPt;
Paint mTextPaint, mTileEdgePaint;
final static int VALID = 0;
public Sudoku(Context context){
super(context);
initializeBoard();
}
public Sudoku(Context context, AttributeSet attrs){
super(context, attrs);
initializeBoard();
}
#Override
protected void onDraw(Canvas canvas){
/* There are some codes here */
Log.d("LogTest","OnDraw Complete");
}
public void initializeBoard(){
for (int x=0; x< mWidth; x++){
for (int y=0; y< mHeight; y++){
mBoard[x][y] = 0;
}
}
invalidate();
}
public boolean onTouch(View v, MotionEvent event){
Log.d("LogTest","Touched?"); /* LOG NOT ACTIVE HERE */
if(event.getAction() == MotionEvent.ACTION_DOWN){
mXNow = getBoardX(event.getX());
Log.d("LogTest","" + mXNow); /* LOG NOT ACTIVE HERE */
mYNow = getBoardY(event.getY());
Log.d("LogTest","" + mYNow); /* LOG NOT ACTIVE HERE */
mBoard[mXNow][mYNow] = mBoard[mXNow][mYNow] + 1;
invalidate();
return true;
}
else return false;
}
int getBoardX(float scrx){
int x = (int)((scrx) / mCellWidth);
if (x < 0) x = 0;
if (x > 8) x= 8;
return x;
}
int getBoardY(float scry){
int y = (int)((scry) / mCellHeight);
if (y < 0) y = 0;
if (y > 8) y = 8;
return y;
}
}
Edit: added activity XML file.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:id="#+id/activity_sudoku"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="snacker.nonogramsolver.SudokuActivity">
<snacker.nonogramsolver.Sudoku
android:id="#+id/SudokuGrid"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="#+id/btn_clear"
android:layout_width="150dp"
android:layout_height="30dp"
android:layout_weight="0.06"
android:text="Clear" />
</LinearLayout>
You cannot directly add touchListener by just creating object of
Sudoku class. You should add view in xml or programatically.
Your Activity
public class MyActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//initializing custom views
MyCustomView1 myCustomView1 = new MyCustomView1(parameterList);
MyCustomView2 myCustomView2 = new MyCustomView2(parameterList);
//adding both custom views to the main activity
mainView.addView(myCustomView1);
mainView.addView(myCustomView1);
//adding custom listener to the custom view 1
myCustomView1.setCustomEventListener(new OnCustomEventListener() {
#Override
public void onEvent() {
//firing an event of custom view 1
Toast.makeText(MainActivity.this, "Touched custom view 1",
Toast.LENGTH_SHORT).show();
}
});
//adding custom listener to the custom view 2
myCustomView2.setCustomEventListener(new OnCustomEventListener() {
#Override
public void onEvent() {
//firing an event of custom view 2
Toast.makeText(MainActivity.this, "Touched custom view 2",
Toast.LENGTH_SHORT).show();
}
});
}
}
Your CustomView 1
public class MyCustomView1 extends LinearLayout{
OnCustomEventListener myCustomEventListener;
public MyCustomView1(ParameterList){
super(ContextFromParameterList);
//Just adding something to the custom view 1 in order to distinguish it on the screen
TextView tv = new TextView(ContextFromParameterList);
tv.setText("Hello world from custom view 1");
addView(tv);
this.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
//delegating one event to another (delegating touch event to custom event)
if (MyCustomView1.this.myCustomEventListener != null)
MyCustomView1.this.myCustomEventListener.onEvent();
return false;
}
}); }
public void setCustomEventListener(OnCustomEventListener
eventListener) {
//setting custom listener from activity
myCustomEventListener = eventListener; } }
Your CustomView2
public class MyCustomView2 extends LinearLayout {
OnCustomEventListener myCustomEventListener;
public MyCustomView2(ParameterList) {
super(ContextFromParameterList);
//Just adding something to the custom view 1 in order to distinguish it on the screen
TextView tv = new TextView(ContextFromParameterList);
tv.setText("Hello world from custom view 2");
addView(tv);
this.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
//delegating one event to another (delegating touch event to custom event)
if (MyCustomView2.this.myCustomEventListener != null)
MyCustomView2.this.myCustomEventListener.onEvent();
return false;
}
});
}
public void setCustomEventListener(OnCustomEventListener eventListener) {
//setting custom listener from activity
myCustomEventListener = eventListener;
}
}
Your listener interface:
public interface OnCustomEventListener{
//interface defines one method. Can be more and methods may have parameters
public void onEvent();
}

Android Animations and functions need to move to activity?

I am working on a small game with touch-motion, bluetooth, and menus. At the moment the code is implemented is in my custom View.
For example vectors of classes that store game-data, vectors for current data and later will there be some threads for animations and timers.
Yet there is no icons for "abilities", but I will implement them too.
Later will there be a process or a service with bluetooth which also calls methods which are at the moment in the custom view class.
I suppose this is a bad design - so I have no concrete idea how I can or should move my functions to for example the activity which holds the custom view and how to let the custom view and activity communicate with each other.
Maybe some of you have advice on what to do.
Here is the activity:
Gamecontroller_Activity:
public class Gamecontroller_Activity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("Enter Function","Enter onCreate Gamecontroler_Activity");
setContentView(R.layout.activity_gamecontroller);
}
}
activity_gamecontroller.xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.calma.Gamecontroller_View
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
And the big custom view class (shorted) Gamecontroller_View.java:
public class Gamecontroller_View extends View implements OnGestureListener{
//Touch
private PointF fingerpointer;
private int totalClickt;
private static final int SIZE = 60;
private Paint mPaint;
//Text Flashes
private Paint textPaint;
private Paint textPaintAction;
private String currentMsg;
private boolean currentMsgShow;
//Drawables (Pictures)
private int monsterscale;
private int monsterMinimumBorderX;
private int monsterMinimumBorderY;
private Bitmap bitmap1,bitmap2;
private HashMap<String, Bitmap> hashmapMonsterStandartBitmap;
Display Informations;
private DisplayMetrics displayMetrics;
private int xDisplayMaximum;
private int yDisplayMaximum;
//Monsters
private Vector<Monster> currentMonsters;
private int monsterCountGlobal;
//Player Stats
private Player playerMe;
//Enemy Player Stats
private Player playerEnemy;
public Gamecontroller_View(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public void initView(){
//display
displayMetrics = new DisplayMetrics();
((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(displayMetrics);
float displayPixelFactor = displayMetrics.widthPixels/displayMetrics.densityDpi;
xDisplayMaximum = displayMetrics.widthPixels ;
yDisplayMaximum = displayMetrics.heightPixels - (3*getStatusBarSizes());
Log.i("Display","displaywidthpixels/displayMetrics: "+xDisplayMaximum);
//yDisplayMaximum
//Enemy Player
playerEnemy = new Player();
//Monsters
monsterscale =10;
monsterMinimumBorderX= Math.min(xDisplayMaximum,yDisplayMaximum)/monsterscale;
monsterMinimumBorderY= Math.max(xDisplayMaximum,yDisplayMaximum)/monsterscale;
hashmapMonsterStandartBitmap = new HashMap<String,Bitmap>();
currentMonsters = new Vector<Monster>();
monsterCountGlobal = 0;
Log.i("display","Monsterscale: "+monsterscale + " minMonsterBorder: "+monsterMinimumBorderX);
//init Touch detection and draw
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
mPaint.setMaskFilter(new BlurMaskFilter(15, Blur.OUTER));
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
//init Text wich will be drawn
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(30);
textPaintAction = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaintAction.setTextSize(60);
currentMsg = "";
currentMsgShow = false;
//Futher init stuff
initPlayerMe();
initPlayerEnemy();
enemySpawn();
preloadImages();
showDebug();
}
public void initPlayerMe(){
//Player
playerMe = new Player();
playerMe.setlife(100);
playerMe.setMoney(0);
playerMe.setStrength(1);
}
public void initPlayerEnemy(){
//Player
playerEnemy = new Player();
playerEnemy.setlife(100);
playerEnemy.setMoney(0);
playerEnemy.setStrength(1);
}
public Vector<Dimension> findPlaceForMonsters(int n){
//First Collect allready existing Monster Coordinates
Vector <Dimension> currentPlaces = new Vector<Dimension>();
Vector <Dimension> newPlaces = new Vector<Dimension>();
for(int i = 0; i< currentMonsters.size();i++){
if (currentMonsters.elementAt(i) != null){
currentPlaces.add(currentMonsters.elementAt(i).getDimension());
}
}
for (int i=0; i < n ;i++){
newPlaces.add(new Dimension(getRandomNumberBetween(0, xDisplayMaximum-monsterMinimumBorderX),
getRandomNumberBetween(0, yDisplayMaximum-monsterMinimumBorderY)));
Log.i("randomPlaces","Point xy: " + newPlaces.lastElement().getX()+ " "+newPlaces.lastElement().getY());
}
Log.i("findPlfaceForMonsters",this.monsterMinimumBorderX+" "+this.monsterMinimumBorderY);
return newPlaces;
}
public void enemySpawn(){
int tempCount =0;
Vector<Dimension> newPlaces = findPlaceForMonsters(6);
for(int i=0; i < 2;i++){
currentMonsters.add(new MonsterMedium(monsterCountGlobal));
currentMonsters.lastElement().setDimension(new Dimension(newPlaces.elementAt(tempCount).getX(),newPlaces.elementAt(tempCount).getY(),monsterMinimumBorderX,monsterMinimumBorderY));
monsterCountGlobal++;
tempCount++;
}
for(int i=0; i < 2;i++){
currentMonsters.add(new MonsterSmall(monsterCountGlobal));
currentMonsters.lastElement().setDimension(new Dimension(newPlaces.elementAt(tempCount).getX(),newPlaces.elementAt(tempCount).getY(),monsterMinimumBorderX,monsterMinimumBorderY));
monsterCountGlobal++;
tempCount++;
}
for(int i=0; i < 2;i++){
currentMonsters.add(new MonsterHeavy(monsterCountGlobal));
currentMonsters.lastElement().setDimension(new Dimension(newPlaces.elementAt(tempCount).getX(),newPlaces.elementAt(tempCount).getY(),monsterMinimumBorderX,monsterMinimumBorderY));
monsterCountGlobal++;
tempCount++;
}
}
public void attackMonster(int id){
for (int i=currentMonsters.size()-1; i >= 0; i--){
if (currentMonsters.elementAt(i).getID() == id){
int restlife = currentMonsters.elementAt(i).setDamge(this.playerMe.getStrength());
lifeOfMonsterChanged(currentMonsters.elementAt(i).getID(),i,restlife);
break;
}
}
}
public void lifeOfMonsterChanged(int id,int index, int life){
if (life <= 0){
Log.i("MonsterTouchted", "Monster tot");
currentMonsters.removeElementAt(index);
}
else{
Log.i("MonsterTouchted", "Monster "+id+" restlife: "+life);
//effekte? (shake?) farbE?
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// get pointer index from the event object
int pointerIndex = event.getActionIndex();
// get pointer ID
int pointerId = event.getPointerId(pointerIndex);
Log.i("touch","event.getPointerID(): "+pointerId);
// get masked (not specific to a pointer) action
int maskedAction = event.getActionMasked();
switch (maskedAction) {
//Detection of a finger touch
case MotionEvent.ACTION_DOWN:
totalClickt = totalClickt+1;
//attackTheMonster(currentPlayer.attack());
fingerpointer = new PointF();
fingerpointer.x = event.getX(0);
fingerpointer.y = event.getY(0);
for (int i=currentMonsters.size()-1; i >= 0; i--){
if(currentMonsters.elementAt(i).getDimension().contains((int)fingerpointer.x, (int)fingerpointer.y)){
Log.i("MonsterTouchted","MonsterTouched: index: "+i);
attackMonster(currentMonsters.elementAt(i).getID());
break;
}
}
case MotionEvent.ACTION_POINTER_DOWN:
{
// Optional more than one finger
break;
}
case MotionEvent.ACTION_MOVE:
{ // a pointer was moved
if (fingerpointer != null) {
fingerpointer.x = event.getX(0);
fingerpointer.y = event.getY(0);
}
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL: {
fingerpointer = null;
break;
}
}
invalidate();
return true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw all pointers
if (fingerpointer != null){
mPaint.setColor(colors[0]);
canvas.drawCircle(fingerpointer.x, fingerpointer.y, SIZE, mPaint);
}
// draw mosnters
for(int i=0; i < currentMonsters.size();i++){
if( currentMonsters.elementAt(i) != null){
canvas.drawBitmap(hashmapMonsterStandartBitmap.get(currentMonsters.elementAt(i).getImagePath()), currentMonsters.elementAt(i).getDimension().getX(), currentMonsters.elementAt(i).getDimension().getY(), mPaint); //bitmap, abstand left, abstand top, paint
} else{
Log.i("Failure","Draw monster nullpointer bei index: "+i);
}
}
//draw extra texts
if(currentMsgShow){
Log.i("onDraw","enter currenMsgShow");
if(displayMetrics != null){
int textsize = (int) textPaintAction.measureText(currentMsg);
int sidespacing = (displayMetrics.widthPixels - textsize)/2;
canvas.drawText(currentMsg, sidespacing, displayMetrics.heightPixels/5 , textPaintAction);
}
}
//Draw extratext
canvas.drawText( "Total Clickt: " + totalClickt, 10, 40 , textPaint);
}
}
Project:
Make those changes:
1) in your activity_gamecontroller.xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.calma.Gamecontroller_View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/myGameController"/>
</RelativeLayout>
2) in your Gamecontroller_Activity:
public class Gamecontroller_Activity extends Activity {
Gamecontroller_View mGameControllerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("Enter Function","Enter onCreate Gamecontroler_Activity");
setContentView(R.layout.activity_gamecontroller);
mGameControllerView = (Gamecontroller_View) findViewById(R.id.myGameController);
}
}
3) now you can call for example mGameControllerView.initPlayerMe(); from any method in your Gamecontroller_Activity .
This is an example:
public class Gamecontroller_Activity extends Activity {
Gamecontroller_View mGameControllerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("Enter Function","Enter onCreate Gamecontroler_Activity");
setContentView(R.layout.activity_gamecontroller);
mGameControllerView = (Gamecontroller_View) findViewById(R.id.myGameController);
testMethod();
}
private void testMethod(){
mGameControllerView.enemySpawn();
}
}

Relative Layout get Width/Height return 0

I need to get width and height of Relative layout, however I do not know when the Relative Layout is ready to provide me these two attributes. My activity has several tabs and I call the getWidth() and getHeight() in onCreateView() after inflater.inflate(R.layout.fragment_pizza, container, false);, however it returns 0 for both of them, so they are not apparently ready. Is there some kind of event like afterCreateView() or something similar where I can call these two methods and get the actual width and height?
Code:
public class PizzaFragment extends Fragment {
private static final String TAG = "PizzaFragment";
private Controller controller;
private static final int BUTTON_WIDTH = 70;
private static final int BUTTON_HEIGHT = 20;
private static final int MARGIN_LEFT = 80;
private static final int MARGIN_BOTTOM = 30;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
controller = Controller.getInstance();
controller.loadProducts("pizza", getActivity().getApplicationContext());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_pizza, container, false);
RelativeLayout layout = (RelativeLayout) view.findViewById(R.id.rl_order_pizza);
Log.d(TAG, "Width: " + layout.getWidth());
Log.d(TAG, "Height: " + layout.getHeight());
int currentX = 10;
int currentY = 10;
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(BUTTON_WIDTH, BUTTON_HEIGHT);
for (Product product: controller.getProducts("pizza")){
Button tempButton = new Button(getActivity());
tempButton.setId(product.getId());
tempButton.setText(product.getName());
if (layout.getWidth() < currentX + MARGIN_LEFT){
currentX = 10;
currentY = MARGIN_BOTTOM;
}
else{
currentX += MARGIN_LEFT;
}
Log.d(TAG, "CurrentY: " + currentY);
Log.d(TAG, "CurrentX: " + currentX);
layoutParams.leftMargin = currentX;
layoutParams.bottomMargin = currentY;
tempButton.setLayoutParams(layoutParams);
layout.addView(tempButton);
}
return view;
}
}
My suggestion is to use a global layout listener like this in onCreateView:
YOUR_LAYOUT_INSTANCE = view.findViewById(R.id.YOUR_LAYOUT_ID);
...
YOUR_LAYOUT_INSTANCE.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
// gets called after layout has been done but before display.
if (Build.VERSION.SDK_INT < 16) {
YOUR_LAYOUT_INSTANCE.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
YOUR_LAYOUT_INSTANCE.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
// get width and height
}
});
addOnGlobalLayoutListener is deprecated use removeOnGlobalLayoutListener .For better handling extending the solution provided above by #fasteque
YOUR_LAYOUT_INSTANCE.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
// gets called after layout has been done but before display.
if (Build.VERSION.SDK_INT < 16) {
YOUR_LAYOUT_INSTANCE.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
else {
YOUR_LAYOUT_INSTANCE.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
// get width and height
}
});

Android Gallery zoom in/out

Hi I am using the Gallery widget to show images downloaded from the internet.
to show several images and I would like to have a gradual zoom while people slide up and down on the screen. I know how to implement the touch event the only thing I don't know how to make the whole gallery view grow gradually. I don't want to zoom in on one image I want the whole gallery to zoom in/out gradually.
EDIT3: I manage to zoom the visible part of the gallery but the problem is I need to find a way for the gallery to find out about it and update it's other children too.
What happens is if 3 images are visible then you start zooming and the gallery does get smaller, so do the images but what I would like in this case is more images to be visible but I don't know how to reach this desired effect. Here's the entire code:
public class Gallery1 extends Activity implements OnTouchListener {
private static final String TAG = "GalleryTest";
private float zoom=0.0f;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
Gallery g;
LinearLayout layout2;
private ImageAdapter ad;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gallery_1);
layout2=(LinearLayout) findViewById(R.id.layout2);
// Reference the Gallery view
g = (Gallery) findViewById(R.id.gallery);
// Set the adapter to our custom adapter (below)
ad=new ImageAdapter(this);
g.setAdapter(ad);
layout2.setOnTouchListener(this);
}
public void zoomList(boolean increase) {
Log.i(TAG, "startig animation");
AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(g, "scaleX", zoom),
ObjectAnimator.ofFloat(g, "scaleY", zoom)
);
set.addListener(new AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationEnd(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
set.setDuration(100).start();
}
public class ImageAdapter extends BaseAdapter {
private static final int ITEM_WIDTH = 136;
private static final int ITEM_HEIGHT = 88;
private final int mGalleryItemBackground;
private final Context mContext;
private final Integer[] mImageIds = {
R.drawable.gallery_photo_1,
R.drawable.gallery_photo_2,
R.drawable.gallery_photo_3,
R.drawable.gallery_photo_4,
R.drawable.gallery_photo_5,
R.drawable.gallery_photo_6,
R.drawable.gallery_photo_7,
R.drawable.gallery_photo_8
};
private final float mDensity;
public ImageAdapter(Context c) {
mContext = c;
// See res/values/attrs.xml for the <declare-styleable> that defines
// Gallery1.
TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
mGalleryItemBackground = a.getResourceId(
R.styleable.Gallery1_android_galleryItemBackground, 1);
a.recycle();
mDensity = c.getResources().getDisplayMetrics().density;
}
public int getCount() {
return mImageIds.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
convertView = new ImageView(mContext);
imageView = (ImageView) convertView;
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setLayoutParams(new Gallery.LayoutParams(
(int) (ITEM_WIDTH * mDensity + 0.5f),
(int) (ITEM_HEIGHT * mDensity + 0.5f)));
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(mImageIds[position]);
return imageView;
}
}
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE
&& event.getPointerCount() > 1) {
midPoint(mid, event);
if(mid.y > start.y){
Log.i(TAG, "Going down (Math.abs(mid.y - start.y)= "+(Math.abs(mid.y - start.y))+" and zoom="+zoom); // going down so increase
if ((Math.abs(mid.y - start.y) > 10) && (zoom<2.5f)){
zoom=zoom+0.1f;
midPoint(start, event);
zoomList(true);
}
return true;
}else if(mid.y < start.y){
Log.i(TAG, "Going up (Math.abs(mid.y - start.y)= "+(Math.abs(mid.y - start.y))+" and zoom="+zoom); //smaller
if ((Math.abs(mid.y - start.y) > 10) &&(zoom>0.1)){
midPoint(start, event);
zoom=zoom-0.1f;
zoomList(false);
}
return true;
}
}
else if (event.getAction() == MotionEvent.ACTION_POINTER_DOWN) {
Log.e(TAG, "Pointer went down: " + event.getPointerCount());
return true;
}
else if (event.getAction() == MotionEvent.ACTION_UP) {
Log.i(TAG, "Pointer going up");
return true;
}
else if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.i(TAG, "Pointer going down");
start.set(event.getX(), event.getY());
return true;
}
return false;
// indicate event was handled or not
}
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
I realise I will probably have to extend the Gallery or even another View group or create my own class but I don't know where to start: which method use the one responsible for scaling...
EDIT4: I don't know if he question is clear enough. Here is an example of states:
State one: initial state, we have 3 images in view
State 2: we detect vertical touches going up with 2 fingers = we have to zoom out
state 3: we start zooming = animation on the gallery or on the children???
state 4: gallery detects that it's 3 children are smaller
state 5: gallery adds 1 /more children according to the new available space
LAST UPDATE:
Thanks to all that have posted but I have finally reached a conclusion and that is to not use Gallery at all:
1. It's deprecated
2. It's not customizable enough for my case
If you want to animate several images at once you may want to consider using OpenGl, I am using libgdx library:
https://github.com/libgdx/libgdx
The following ScalingGallery implementation might be of help.
This gallery subclass overrides the getChildStaticTransformation(View child, Transformation t) method in which the scaling is performed. You can further customize the scaling parameters to fit your own needs.
Please note the ScalingGalleryItemLayout.java class. This is necessary because after you have performed the scaling operationg on the child views, their hit boxes are no longer valid so they must be updated from with the getChildStaticTransformation(View child, Transformation t) method.
This is done by wrapping each gallery item in a ScalingGalleryItemLayout which extends a LinearLayout. Again, you can customize this to fit your own needs if a LinearLayout does not meet your needs for layout out your gallery items.
File : /src/com/example/ScalingGallery.java
/**
* A Customized Gallery component which alters the size and position of its items based on their position in the Gallery.
*/
public class ScalingGallery extends Gallery {
public static final int ITEM_SPACING = -20;
private static final float SIZE_SCALE_MULTIPLIER = 0.25f;
private static final float ALPHA_SCALE_MULTIPLIER = 0.5f;
private static final float X_OFFSET = 20.0f;
/**
* Implemented by child view to adjust the boundaries after it has been matrix transformed.
*/
public interface SetHitRectInterface {
public void setHitRect(RectF newRect);
}
/**
* #param context
* Context that this Gallery will be used in.
* #param attrs
* Attributes for this Gallery (via either xml or in-code)
*/
public ScalingGallery(Context context, AttributeSet attrs) {
super(context, attrs);
setStaticTransformationsEnabled(true);
setChildrenDrawingOrderEnabled(true);
}
/**
* {#inheritDoc}
*
* #see #setStaticTransformationsEnabled(boolean)
*
* This is where the scaling happens.
*/
protected boolean getChildStaticTransformation(View child, Transformation t) {
child.invalidate();
t.clear();
t.setTransformationType(Transformation.TYPE_BOTH);
// Position of the child in the Gallery (... +2 +1 0 -1 -2 ... 0 being the middle)
final int childPosition = getSelectedItemPosition() - getPositionForView(child);
final int childPositionAbs = (int) Math.abs(childPosition);
final float left = child.getLeft();
final float top = child.getTop();
final float right = child.getRight();
final float bottom = child.getBottom();
Matrix matrix = t.getMatrix();
RectF modifiedHitBox = new RectF();
// Change alpha, scale and translate non-middle child views.
if (childPosition != 0) {
final int height = child.getMeasuredHeight();
final int width = child.getMeasuredWidth();
// Scale the size.
float scaledSize = 1.0f - (childPositionAbs * SIZE_SCALE_MULTIPLIER);
if (scaledSize < 0) {
scaledSize = 0;
}
matrix.setScale(scaledSize, scaledSize);
float moveX = 0;
float moveY = 0;
// Moving from right to left -- linear move since the scaling is done with respect to top-left corner of the view.
if (childPosition < 0) {
moveX = ((childPositionAbs - 1) * SIZE_SCALE_MULTIPLIER * width) + X_OFFSET;
moveX *= -1;
} else { // Moving from left to right -- sum of the previous positions' x displacements.
// X(n) = X(0) + X(1) + X(2) + ... + X(n-1)
for (int i = childPositionAbs; i > 0; i--) {
moveX += (i * SIZE_SCALE_MULTIPLIER * width);
}
moveX += X_OFFSET;
}
// Moving down y-axis is linear.
moveY = ((childPositionAbs * SIZE_SCALE_MULTIPLIER * height) / 2);
matrix.postTranslate(moveX, moveY);
// Scale alpha value.
final float alpha = (1.0f / childPositionAbs) * ALPHA_SCALE_MULTIPLIER;
t.setAlpha(alpha);
// Calculate new hit box. Since we moved the child, the hitbox is no longer lined up with the new child position.
final float newLeft = left + moveX;
final float newTop = top + moveY;
final float newRight = newLeft + (width * scaledSize);
final float newBottom = newTop + (height * scaledSize);
modifiedHitBox = new RectF(newLeft, newTop, newRight, newBottom);
} else {
modifiedHitBox = new RectF(left, top, right, bottom);
}
// update child hit box so you can tap within the child's boundary
((SetHitRectInterface) child).setHitRect(modifiedHitBox);
return true;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// Helps to smooth out jittering during scrolling.
// read more - http://www.unwesen.de/2011/04/17/android-jittery-scrolling-gallery/
final int viewsOnScreen = getLastVisiblePosition() - getFirstVisiblePosition();
if (viewsOnScreen <= 0) {
super.onLayout(changed, l, t, r, b);
}
}
private int mLastDrawnPosition;
#Override
protected int getChildDrawingOrder(int childCount, int i) {
//Reset the last position variable every time we are starting a new drawing loop
if (i == 0) {
mLastDrawnPosition = 0;
}
final int centerPosition = getSelectedItemPosition() - getFirstVisiblePosition();
if (i == childCount - 1) {
return centerPosition;
} else if (i >= centerPosition) {
mLastDrawnPosition++;
return childCount - mLastDrawnPosition;
} else {
return i;
}
}
}
File : /src/com/example/ScalingGalleryItemLayout.java
public class ScalingGalleryItemLayout extends LinearLayout implements SetHitRectInterface {
public ScalingGalleryItemLayout(Context context) {
super(context);
}
public ScalingGalleryItemLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScalingGalleryItemLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
private Rect mTransformedRect;
#Override
public void setHitRect(RectF newRect) {
if (newRect == null) {
return;
}
if (mTransformedRect == null) {
mTransformedRect = new Rect();
}
newRect.round(mTransformedRect);
}
#Override
public void getHitRect(Rect outRect) {
if (mTransformedRect == null) {
super.getHitRect(outRect);
} else {
outRect.set(mTransformedRect);
}
}
}
File : /res/layout/ScaledGalleryItemLayout.xml
<?xml version="1.0" encoding="utf-8"?>
<com.example.ScalingGalleryItemLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gallery_item_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical"
android:padding="5dp" >
<ImageView
android:id="#+id/gallery_item_image"
android:layout_width="360px"
android:layout_height="210px"
android:layout_gravity="center"
android:antialias="true"
android:background="#drawable/gallery_item_button_selector"
android:cropToPadding="true"
android:padding="35dp"
android:scaleType="centerInside" />
<TextView
android:id="#+id/gallery_item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#drawable/white"
android:textSize="30sp" />
</com.example.ScalingGalleryItemLayout>
To keep the state of the animation after it is done, just do this on your animation:
youranim.setFillAfter(true);
Edit :
In my project, I use this method and i think, it's help you :
http://developer.sonymobile.com/wp/2011/04/12/how-to-take-advantage-of-the-pinch-to-zoom-feature-in-your-xperia%E2%84%A2-10-apps-part-1/
U can do Image Zoom pinch option for gallery also.
by using below code lines:
you can download the example.
https://github.com/alvinsj/android-image-gallery/downloads
I hope this example will help to u..if u have any queries ask me.....
This is solution
integrate gallery component in android with gesture-image library
gesture-imageView
And here is full sample code
SampleCode

Events of more instances of the same custom View

I'm new with Android.
In my project I have the custom View MyView with the follow code
public class MyView extends View {
private final Bitmap baseBitmap = BitmapFactory.decodeResource(
getResources(), R.drawable.myImage);
private final Matrix matrix;
private boolean active = true;
public MyView(Context context, Matrix matrix) {
super(context);
this.matrix = matrix;
this.setFocusable(true);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (active) {
System.out.println("draw "+this.getId());
canvas.drawBitmap(baseBitmap, matrix, null);
} else {
...
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
System.out.println("--------->"+this.getId());
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
this.matrix.setTranslate(event.getX()-(baseBitmap.getWidth()/2), event.getY()-(baseBitmap.getHeight()/2));
this.invalidate();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
this.active = false;
}
return true;
}
In my Activity, I instantiate MyView many times and then add them to the main layout. This is its code:
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Display display = getWindowManager().getDefaultDisplay();
float cx = display.getWidth() / 2, cy = display.getHeight() / 2;
int radius = 80;
double distance = 0, distancePoint = 0;
final int flags = PathMeasure.POSITION_MATRIX_FLAG
| PathMeasure.TANGENT_MATRIX_FLAG;
float length = 0;
setContentView(R.layout.main);
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.main_view);
Path pathCircle = new Path();
pathCircle.addCircle(cx, cy, radius, Direction.CW);
PathMeasure meas = new PathMeasure(pathCircle, false);
int nObject = 10;
length = meas.getLength();
distance = length/nObject;
int i = 0;
while(i<nObject){
Matrix m = new Matrix();
meas.getMatrix((float)distancePoint, m, flags);
MyView myView = new MyView(this, m);
System.out.println(myView.toString());
myView.setId(i);
mainLayout.addView(myView,i);
i++;
distancePoint = distance*i;
}
}
}
At runtime, when I touch any MyView element I always get the last. With "System.out.println("--------->"+this.getId());" I can see that the id of the touched element is always the last, even if I toch the first or any other element. Actualy, I just can move the last element.
Does anyone know why can't I get the event of the right istance of MyView touched?
(I hope my question is clear)
Thanks
I changed the code adding the onMeasure method. I used the code of a tutorial, dimensions are not specific for my image. The views are drawn and the result is the same, unfortunately with the same problem. I post the layout xml too, maybe could be useful.
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Display display = getWindowManager().getDefaultDisplay();
float cx = display.getWidth() / 2, cy = display.getHeight() / 2;
int radius = 80;
double distance = 0, distancePoint = 0;
final int flags = PathMeasure.POSITION_MATRIX_FLAG
| PathMeasure.TANGENT_MATRIX_FLAG;
float length = 0;
setContentView(R.layout.main);
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.main_view);
Path pathCircle = new Path();
pathCircle.addCircle(cx, cy, radius, Direction.CW);
PathMeasure meas = new PathMeasure(pathCircle, false);
int nObject = 10;
length = meas.getLength();
distance = length/nObject;
int i = 0;
while(i<nObject){
Matrix m = new Matrix();
meas.getMatrix((float)distancePoint, m, flags);
MyView myView = new MyView(this, m);
System.out.println(myView.toString());
myView.setId(i);
nt spec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
myView.measure(spec, spec);
mainLayout.addView(myView,i);
i++;
distancePoint = distance*i;
}
}
}
public class MyView extends View {
private final Bitmap baseBitmap = BitmapFactory.decodeResource(
getResources(), R.drawable.myImage);
private final Matrix matrix;
private boolean active = true;
public MyView(Context context, Matrix matrix) {
super(context);
this.matrix = matrix;
this.setFocusable(true);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (active) {
System.out.println("draw "+this.getId());
canvas.drawBitmap(baseBitmap, matrix, null);
} else {
...
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
System.out.println("--------->"+this.getId());
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
this.matrix.setTranslate(event.getX()-(baseBitmap.getWidth()/2), event.getY()-(baseBitmap.getHeight()/2));
this.invalidate();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
this.active = false;
}
return true;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int chosenWidth = chooseDimension(widthMode, widthSize);
int chosenHeight = chooseDimension(heightMode, heightSize);
int chosenDimension = Math.min(chosenWidth, chosenHeight);
setMeasuredDimension(chosenDimension, chosenDimension);
}
private int chooseDimension(int mode, int size) {
if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) {
return size;
} else { // (mode == MeasureSpec.UNSPECIFIED)
return getPreferredSize();
}
}
// in case there is no size specified
private int getPreferredSize() {
return 300;
}
}
The main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="#+id/main_view"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FF66FF33">
</RelativeLayout>
I'm pretty sure that it's because you're basically piling up your views at the top left corner of your RelativeLayout. So, only the uppermost (the last one added) is touchable.
I think that if you try adding them to a LinearLayout, as a test, you'll see that your view works. Setting LayoutParams for a RelativeLayout programmatically is not very comfy IMHO.
EDIT
I tried your code. The fact is that your views are just made to be drawn one over the other, or else the overall drawing wouldn't come, so my first guess is right (the uppermost covers the others - even in its transparent parts)(btw try Hierarchy Viewer and you can see that yourself). So you need to do your job in a single view, or handle the touches like this:
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if(!isPetaloTouched()) {// check if the actual drawing was touched
return false; // discard the event so that it reaches
// the underlying view
}
//......
See this post for an explanation of how events work in Android.
Both ways would need an isPetaloTouched() logic to detect if/which drawing must be moved, but the first would be more efficient of course.
Also, forget about the onMeasure() thing, I thought that could help giving the view a size around which to wrap, so that it wouldn't fill its parent and aligning views aside would make sense. However, be sure that the touch would work if the views were not piled up.
(...allora mPetali stava proprio per petali!)

Categories

Resources