setBackgroundResource for button not working - android

I am new to android app development. I am trying to build 2048 game. I used images for tiles and loaded them for every swipe. At first i got memoryOutOfBounds Exception. Later i changed the largeHeap to true and it worked but is bit slow. So, i replaced the images with xml background and used buttons. But now my app is not working. onSwipe functions are not getting invoked. After swiping for many number of times then i am able to make a move that too woth incorrect background colours. Please help me figure this out.
Button b[][] =new Button[4][4];
GestureDetector gestureDetector;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int idd[][] = {{R.id.block00, R.id.block01, R.id.block02, R.id.block03},
{R.id.block10, R.id.block11, R.id.block12, R.id.block13},
{R.id.block20, R.id.block21, R.id.block22, R.id.block23},
{R.id.block30, R.id.block31, R.id.block32, R.id.block33}};
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
b[i][j] = (Button)findViewById(idd[i][j]);
start();
draw();
gestureDetector = new GestureDetector(MainActivity.this, MainActivity.this);
}
code for draw function
public void draw()
{
int i,j;
int img[] = {R.drawable.t0, R.drawable.t2, R.drawable.t4, R.drawable.t8, R.drawable.t16, R.drawable.t32, R.drawable.t64, R.drawable.t128, R.drawable.t256, R.drawable.t512, R.drawable.t1024, R.drawable.t2048, R.drawable.t4096, R.drawable.t8192, R.drawable.t16384, R.drawable.t32768, R.drawable.t65536, R.drawable.t131072};
for(i=0;i<4;i++)
for(j=0;j<4;j++)
{
if(grid[i][j]!=0)
b[i][j].setText(Integer.toString(grid[i][j]));
b[i][j].setBackgroundResource(img[log2(grid[i][j])]);
}
TextView tv=(TextView)findViewById(R.id.score);
TextView tv1=(TextView)findViewById(R.id.best);
tv.setText(Integer.toString(score));
tv1.setText(Integer.toString(best));
}
When i changed the xml object from button to ImageView and the code inside draw from setBackgroundResource to setImageResource, it is working fine.
one of the drawable xml files(t1024.xml)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<padding
android:left="4dp"
android:top="4dp"
android:right="4dp"
android:bottom="4dp"/>
<corners android:radius="6dp"/>
<solid android:color="#1a1d23"/>
All drawable resources contain the same code, i just changed the android:color attribute.

Related

Android: How to put custom elements on a circle/target

I need to create a sort of target and add objects to it, that have different colors and do different things when I click directly on them.
Any suggestion on how to achieve this? Maybe there is a library which I can use?
The formal solution is
Create roundedshape.xml inside drawable
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadiusRatio="4"
android:shape="ring"
android:thicknessRatio="5"
android:useLevel="false">
<solid android:color="#af08d7" />
<size
android:width="25dip"
android:height="25dip"></size>
</shape>
</item>
</layer-list>
Add RelativeLayout having android:background="#drawable/roundedshape"
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="300dp"
android:padding="50dp"
android:background="#drawable/roundedshape"
android:id="#+id/myRelativeLayout"
>
</RelativeLayout>
In your Activity add these codes to dynamically generate ImageButtons and add in Layout.
RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.myRelativeLayout);
for (int j = 0; j < 4; j++) {
ImageButton myImageButton = new ImageButton(this); //generate ImageButton
myImageButton.setId(j); //Set Id of button
//Generate Random Number to place ImageButtons in random position
int min = 40;
int max = 60;
Random r = new Random();
int randomNum = r.nextInt(max - min + 1) + min;
myImageButton.setBackgroundResource(R.drawable.chatbox); //Set background of ImageButton
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 100);
params.leftMargin = randomNum+j*randomNum; //Generate left margin dynamically
params.topMargin = randomNum +j*randomNum; //Generate right margin dynamically
relativeLayout.addView(myImageButton, params); //Add view
myImageButton.setOnClickListener(getButtonAndDoAction(myImageButton)); //Add OnClickListener
}
Add this method in Activity to handle the click event of your Image Buttons.
View.OnClickListener getButtonAndDoAction(final ImageButton button) {
return new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(MainActivity.this, "button clicked" +button.getId(), Toast.LENGTH_SHORT).show();
}
};
RESULT :
NOTE: I have added comments to make codes clear as possible
You could draw your image as:
Separate views - like in provided answer using RelativeLayout
Draw on canvas
Use opengl/existing graphics libraries.
It depends on your goals, maybe you need custom layout, maybe some sprites in your game or maybe bitmap to save into the file system.

Palette colour overrides Outline

I'm making an app just to check out some of the new L APIs, and I'm particularly interested in the FloatingActionButton and the Palette colour generator. So I set a full screen ImageView to display an HTC wallpaper, I then extract one of the colours with Palette and set it as the background colour of my FAB. However, doing this removes the Outline from my FAB, so it's no longer circular.
I would like to know how, if possible, to stop the Palette overriding the Outline.
The Palette AsyncListener:
MyActivity.java
Palette.generateAsync(BitmapFactory.decodeResource(getResources(),R.drawable.wallpapers_07),
new Palette.PaletteAsyncListener() {
#Override
public void onGenerated(Palette palette) {
PaletteItem item = palette.getLightVibrantColor();
ImageButton button = (ImageButton) findViewById(R.id.fab);
if (item != null) {
button.setBackgroundColor(item.getRgb());
}
}
});
Outline in MyActivity.java
int size = getResources().getDimensionPixelSize(R.dimen.fab_size);
Outline outline = new Outline();
outline.setOval(0, 0, size, size);
findViewById(R.id.fab).setOutline(outline);
FAB background drawable
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">
<item>
<shape android:shape="oval">
<solid android:color="?android:colorAccent"/>
</shape>
</item>
You are replacing the background drawable (RippleDrawable) with a color (ColorDrawable). Instead, you want to change the color of the shape (GradientDrawable) contained with the background drawable.
Try changing the color filter instead:
findViewById(R.id.fab).getBackgroundDrawable().setColorFilter(
new PorterDuffColorFilter(item.getRgb(), Mode.SRC_IN));
If you're changing the color often, you can just cache the color filter object and use setColor(int) followed by findViewById(R.id.fab).invalidate() to update the view.

Unexpected LayerDrawable behavior when drawing layers containing InsetDrawable's

I am trying to build a LayerDrawable in xml where upper layers will occasionally completely obscure lower layers. To make the lower layers smaller, I am using an InsetDrawable to wrap another drawable to make it smaller than the full size of the view. I find unexpectedly, however, that any layers placed on top of the layer containing the inset also has the inset applied to it. I can't find documentation supporting this behavior, and am confused why this would be the case.
In the example below, I make a LayerDrawable with 3 layers. The bottom and top layers contain oval shape drawables that are meant to take up the entire view. The middle layer is a rectangle drawable inside of an InsetDrawable. The code is below:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="oval" >
<solid android:color="#00ff00" />
</shape>
</item>
<item>
<inset
android:insetBottom="4dp"
android:insetLeft="4dp"
android:insetRight="4dp"
android:insetTop="4dp" >
<shape android:shape="rectangle" >
<solid android:color="#ff0000" />
</shape>
</inset>
</item>
<item>
<shape android:shape="oval" >
<solid android:color="#0000ff" />
</shape>
</item>
</layer-list>
Calling setBackgroundDrawable(getResources().getDrawable(drawableId)); in my view produces a green oval that fills the entire view as expected, with a red rectangle inset 4dp as expected, but the blue oval on the top layer is also inset 4dp and drawn completely within the bounds of the red rectangle.
I would expect the blue oval to completely obscure the green oval and most of the red rectangle, but instead it is inset inside the red rectangle. Is there any way to make the blue circle fill the view yet keep it on top?
I also don't see where it is documented, but padding in a LayerDrawable is cumulative. That is, padding at one layer affects the bounds of all higher layers. This is from the source for LayerDrawable:
#Override
protected void onBoundsChange(Rect bounds) {
final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
int padL=0, padT=0, padR=0, padB=0;
for (int i=0; i<N; i++) {
final ChildDrawable r = array[i];
r.mDrawable.setBounds(bounds.left + r.mInsetL + padL,
bounds.top + r.mInsetT + padT,
bounds.right - r.mInsetR - padR,
bounds.bottom - r.mInsetB - padB);
padL += mPaddingL[i];
padR += mPaddingR[i];
padT += mPaddingT[i];
padB += mPaddingB[i];
}
}
(LayerDrawable.getPadding(Rect) follows the same logic.) Since an InsetDrawable uses its insets as padding (as documented), this explains the behavior you're seeing.
I think this is a poor design decision, but you're kind of stuck with it, I'm afraid. I don't think it can be overridden.
Ted's answer is the best answer, but I'll share this workaround that helped me. I was specifically having padding problems with a TextView, so I made a custom TextView instead which ignores the background drawable's padding.
public class HackTextView extends TextView {
public HackTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public HackTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HackTextView(Context context) {
super(context);
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public void setBackground(Drawable background) {
super.setBackground(hackDrawable(background));
}
#Override
public void setBackgroundDrawable(Drawable background) {
super.setBackgroundDrawable(hackDrawable(background));
}
private Drawable hackDrawable(Drawable background){
return new LayerDrawable(new Drawable[]{background}){
#Override
public boolean getPadding(Rect padding) {
padding.set(0, 0, 0, 0);
return false;
}
};
}
}

on draw on an android button

First I'm new to android.
Okay, here goes.
I'm attempting to override the onDraw of a button, because I want to create a different styled button.. Something ever so slightly different.
Now I can draw the background quite easily, but I can't for the life of me figure out why I have no text on my button.
public class TriButton extends Button {
private Paint m_paint = new Paint();
private int m_color = 0XFF92C84D; //LIKE AN OLIVE GREEN..
public TriButton(Context context) {
super(context);
setBackgroundColor(Color.BLACK);
}
public void onDraw(Canvas iCanvas) {
//draw the button background
m_paint.setColor(m_color);
iCanvas.drawRoundRect(new RectF(0, 0,getWidth(),getHeight()), 30, 30, m_paint);
//draw the text
m_paint.setColor(Color.WHITE);
iCanvas.drawText( "bash is king", 0, 0, m_paint);
}
public static RelativeLayout.LayoutParams GetRelativeParam(int iLeft, int iTop, int iWidth, int iHeight){
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(iHeight, iWidth);
params.leftMargin = iLeft;
params.topMargin = iTop;
return params;
}
}
Here's the code that creates the button.
RelativeLayout relLay = new RelativeLayout(this);
m_button = new TriButton(this);
setContentView(relLay);
relLay.addView(m_button, m_button.GetRelativeParam(0,0,100,500) );
Now everything I've read has me expecting to see text in my olive green button oval button.
The olive green oval shows up, but it doesn't have text in it.. It is a void. A green smudge that laughs at me and reminds me with it's silence, that I am utterly alone :(.
Normally you would do that via xml.
for examle put the following in the layout of your custom class:
android:background="#drawable/shape"
and then something like that which would be shape.xml placed in /drawable.
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="2px"
android:color="#555555"/>
<corners
android:radius="10px"/>
<gradient
android:startColor="#000000"
android:endColor="#ffffff"
android:angle="90"/>
</shape>
This example creates a rounded rectangle with a border and a gradient in it. Let me know if you need further explanation.
See http://developer.android.com/guide/topics/ui/themes.html
Ok, I figured, it's not visible because coordinates are (0,0) which is bottom left of the button, so text is not visible. Try this and it works:
iCanvas.drawText( "bash is king", 0, 15, m_paint);
Olive green is a good choice btw :)
To draw text in your button, get rid of the call to drawText() within the onDraw of your button class. All you need to do is call setText on the instance of the button since Button extends view:
m_button.setText("bash is king");
Also, to make a custom button, you may want to consider just using an Image and assigning an OnClickListener to it.

How to make continuously running TransitionDrawable animation in Android?

I'm trying to make an animated logo. It consists of two static images.
I would to like to achieve a cross-fading effect.
I've done it with the use of TransitionDrawable, set the crossFadeEnabled and everything looks nice.
The thing is that I need to be running in circle. How can it be achieved ?
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/image_expand">
<item android:drawable="#drawable/image_collapse">
</transition>
Resources res = mContext.getResources();
TransitionDrawable transition = (TransitionDrawable) res.getDrawable(R.drawable.expand_collapse);
ImageView image = (ImageView) findViewById(R.id.toggle_image);
image.setImageDrawable(transition);
This the code from google which runs perfectly.
The most importantn thing is that in needs to work under Android 1.6.
I managed to get the transition drawable to work via a handler method that reverses direction after the transition from drawable1 to drawable2. In my XML's :
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="#drawable/background_animation1"/>
<item android:drawable="#drawable/background_animation2"/>
</transition>
The drawables are gradients :
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<corners android:topLeftRadius = "10dp" android:topRightRadius="10dp" android:bottomLeftRadius="10dp" android:bottomRightRadius="10dp"/>
<gradient
android:startColor="#d200ff"
android:centerColor="#4e00ff"
android:endColor="#006cff"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<size android:width="900dp" android:height="500dp"/>
<corners android:topLeftRadius = "10dp" android:topRightRadius="10dp" android:bottomLeftRadius="10dp" android:bottomRightRadius="10dp"/>
<gradient
android:startColor="#006cff"
android:centerColor="#ff6600"
android:endColor="#d200ff"/>
</shape>
In my initialisation code :
trans = (TransitionDrawable) getResources().getDrawable(R.drawable.transition);
trans.setCrossFadeEnabled(true);
backgroundimage.setImageDrawable(trans);
....
handlechange();
And the most important bit in the handler code; note the flag that is running globally. I got this running on Gingerbread and Kitkat;
void handlechange1()
{
Handler hand = new Handler();
hand.postDelayed(new Runnable()
{
#Override
public void run()
{
change();
}
private void change()
{
if (flag)
{
trans.startTransition(8000);
flag = false;
} else
{
trans.reverseTransition(8000);
flag = true;
}
handlechange1();
}
}, 8000);
}
There is not really a built-in way to do this. TransitionDrawable is not designed with an infinite looping animation function. The easiest recommendation would be to use an Animation (alpha, scale, translate, etc.) on a View containing just one of your Drawables if you can.
A fairly easy hack would be to add a Handler and callback to your custom View holding your TransitionDrawable. When the View is created, the Handler can be set to your transition interval. The View would also implement Handler.Callback and inside its handleMessage(Message) method, it would call reverseTransition(int) on your TransitionDrawable.
A rough example is below:
public class myView extends View implements Handler.Callback {
private Handler mHandler = new Handler(this);
private int mDelay = 1000; // Delay in milliseconds.
private Runnable mEvent = new Runnable() {
public void run() {
mHandler.removeCallbacks(mEvent);
mHandler.postDelayed(mEvent, mDelay);
Message message = mHandler.obtainMessage();
mHandler.sendMessage(message);
}
};
public View(Context context) {
super(context);
// Set your background TransitionDrawable.
setBackgroundDrawable(...);
}
public handleMessage(Message message) {
TransitionDrawable drawable = (TransitionDrawable) getBackgroundDrawable();
drawable.reverseTransition(mDelay);
}
public void start() {
mHandler.post(mEvent);
}
public void stop() {
mHandler.removeCallbacks(mEvent);
}
}
Call start() to start your continuous transition, stop() to stop it. It is a bit like creating your own animation, but it works in a pinch.

Categories

Resources