setting alpha value to ImageView - android

I am using the following code to set the alpha value of an ImageView (this should be compatible with all devices, even pre API 11)
AlphaAnimation alpha = new AlphaAnimation(0.85F, 0.85F);
alpha.setDuration(0); // Make animation instant
alpha.setFillAfter(true); // Tell it to persist after the animation ends
ImageView view = (ImageView) findViewById(R.id.transparentBackground);
view.startAnimation(alpha);
However, when I open the app on devices running on gingerbread and below, the imageView is completely transparent but on devices running on honeycomb or higher, the alpha value is set to .85 and the imageView is displayed perfectly.
How can make this happen on gingerBread as well?

An easy way to get this to work is to use the NineOldAndroids project which ports the Honeycomb animation API back to older versions including AlphaAnimation. See http://nineoldandroids.com/.
So, using the ObjectAnimator would be something like this:
ObjectAnimator.ofFloat(imageView, "alpha", .85f).start();

You have a function to do it (has been deprecated because of the new view's generic way of handling transparency but can be used safely on Android 2.x):
myImageView.setAlpha(128); // range [0, 255]
You'll have to implement a custom animation though. This can be done with a handler for instance:
Handler animationHandler = new Handler() {
public void handleMessage(Message msg) {
int currentAlpha = msg.arg1;
int targetAlpha = msg.arg2;
if (currentAlpha==targetAlpha) return;
else {
if (currentAlpha<targetAlpha) --currentAlpha;
else ++currentAlpha;
imageView.setAlpha(currentAlpha);
sendMessageDelayed(obtainMessage(0, currentAlpha, targetAlpha), 10);
}
}
}
// Show imageview
animationHandler.sendMessage(animationHandler.obtainMessage(0, currentAlpha, 255));
// Hide imageview
animationHandler.sendMessage(animationHandler.obtainMessage(0, currentAlpha, 0));
Above code is not memory-leak safe (handlers should be static and should keep weak references to context and views
You should improve it to allow controlling animation speed, ...
You need to keep current alpha around because imageView does not have a getAlpha method.

Ok, lets create an custom imageview, it solves the problem , by overriding the onDraw :)
AlphaImageView.java
package com.example.shareintent;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.ImageView;
public class AlphaImageView extends ImageView {
public AlphaImageView(Context context) {
super(context);
}
public AlphaImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AlphaImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onDraw(Canvas canvas){
canvas.saveLayerAlpha(0, 0, canvas.getWidth(), canvas.getHeight(), 0x66, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);
super.onDraw(canvas);
}
}
your activity xml
<com.example.shareintent.AlphaImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="52dp"
android:layout_marginTop="50dp"
android:src="#drawable/ic_launcher" />

Related

Custom ImageButton, which method to override for simplest RadioButton interface?

I am in the process of making a custom view that is essentially an ImageButton with added logic so it also have the behavior of a RadioButton. All I want to do is have it built into the view that when the user clicks the button the image is changed, an internal boolean is marked true to note it is selected, and an interface method is called to let the RadioGroup it is a part of to unselect all the other views within it. I don't want to impact the existing behavior of the base ImageButton whatsoever.
I've only made one other custom view before and that was by following a tutorial almost exactly to the letter and since there are so many different methods inhereted from View that deal with clicks/touches (i.e. onTouch, onClick, motion event, etc.) taking it all in has left me a bit confused. I am fine writing the interface itself, its the modification of ImageButton where I'm not too sure how to attack it.
So, I ask you all: What method/methods do I need to override to add this simple functionality, while not impacting the current behavior of ImageButton, nor screwing up the ability to set an onTouchListener for the button that will perform additional actions on click without compromising this built in radio button logic? If I need to override something that will mess with the default behavior I mentioned, what do I need to put in the new method to restore that functionality?
This is what I have so far:
public class RadioImageButton extends AppCompatImageButton implements RadioCheckable {
//Default constructor
public RadioImageButton(Context context) {
super(context);
initView();
}
//Constructor with defined attributes
public RadioImageButton(Context context, AttributeSet attrs) {
super(context, attrs);
parseAttributes();
initView();
}
//Constructor with defined attributes and attributes taken from style defaults that aren't defined
public RadioImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//=========================================================================
// Setup
//=========================================================================
private void initView()
{
}
private void parseAttributes()
{
}
}
The approach I would like to take would be something like:
...All other code I already showed
mChecked = false;
#Overide
void onClick(...)
{
mChecked = true;
setImageSource(R.example.checked_image); // Or I can use a selector resource
*Call to Radio Interface*;
mOnTouchListener.onTouch(v, event); //Handle user onTouchListener
}
...
and leave all the other code alone, though I'm sure it isn't quite that simple.
I thought a good start would be trying to find the source code for the default ImageButton class and set mine up to be a near replica so I can understand how it works and then modify from there, but all I could really find was this:
https://android.googlesource.com/platform/frameworks/base/+/android-7.0.0_r35/core/java/android/widget/ImageButton.java
and there is no way that is the actual source because pressing Ctrl+O shows many more functions that ImageButton defines that are not inherited from another class; regardless, that link is not at all helpful as its basically a giant comment with little to no code.
Thanks for any suggestions that will help me accomplish this in the most straightforward way.
EDIT: #pskink - Looking through the code you provided, it seems like it is trying to generate a matrix in order to transform the provided drawable (src) so that it fits into a new rectangle (dst) while maintaining the aspect ratio and positioning (hence ScaleToFit.CENTER). I would assume the destination rectangle would be the bounds of the view the drawable is contained in, which in this case is the RadioButton, but while stepping through the override of the "draw()" method it doesn't quite seem to be doing that, though I'm not quite sure how cavas.concat(matrix) is resolved so I'm not positive. Regardless it doesn't seem to work as intended or I am somehow using it wrong.
While maybe not the most robust method, it seems like the most straightforward, yet effective way to handle what I wanted to do was to leverage the Matrix class and its powerful scaling/transformation tools, specifically "setRectToRect()". Creating a custom view that extends RadioButton instead of ImageButton allowed me to make use of the existing RadioGroup, while manipulating characteristics of the button's drawables in the new classes Constructor achieved the behavior I was looking for.
Custom RadioButton class:
public class RadioImageButton extends android.support.v7.widget.AppCompatRadioButton {
int stateDrawable; //Resource ID for RadioButton selector Drawable
D scaledDrawable; //Post-scaling drawable
public RadioImageButtonTwo(Context context) {
super(context);
initView();
}
public RadioImageButtonTwo(Context context, AttributeSet attrs) {
super(context, attrs);
parseAttributes(attrs);
initView();
}
private void parseAttributes(AttributeSet attrs)
{
TypedArray styledAttrs = getContext().obtainStyledAttributes(attrs,R.styleable.RadioImageButtonTwo);
try {
// Obtain selector drawable from attributes
stateDrawable = styledAttrs.getResourceId(R.styleable.RadioImageButtonTwo_button_sDrawable, R.drawable.test_draw2);
} finally {
styledAttrs.recycle(); //Required for public shared view
}
}
private void initView()
{
scaledDrawable = new D(getResources(),stateDrawable); // Create scaled drawable
setBackground(scaledDrawable); // Apply scaled drawable
setButtonDrawable(android.R.color.transparent); // "Disable" button graphic
}
}
See more on setting up a custom view here: https://developer.android.com/training/custom-views/create-view#customattr
Custom drawable class "D" that includes fitCenter scaling thanks to #pskink:
class D extends StateListDrawable {
private Rect bounds = new Rect();
private RectF src = new RectF();
private RectF dst = new RectF();
private Matrix matrix = new Matrix();
public D(Resources r, int resId) {
try {
XmlResourceParser parser = r.getXml(resId);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (type == XmlPullParser.START_TAG && parser.getName().equals("selector")) {
inflate(r, parser, Xml.asAttributeSet(parser));
break;
}
}
} catch (XmlPullParserException | IOException e) {
e.printStackTrace();
}
}
#Override
public void draw(Canvas canvas) {
Drawable current = getCurrent();
bounds.set(0, 0, current.getIntrinsicWidth(), current.getIntrinsicHeight());
current.setBounds(bounds);
src.set(bounds);
dst.set(getBounds());
matrix.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER);
canvas.concat(matrix);
super.draw(canvas);
}
}
Note that for whatever reason setting the button drawable itself to this custom drawable breaks the scaling, so changing the background to the custom drawable and setting the button drawable to transparent was the only way this worked. This custom drawable could easily be expanded upon to have more scaling type options and another view attribute could be defined to allow the user to choose the scaling type through XML.
This custom ImageView that mimics the (pointed out by pskink aswell) could also prove helpful in this task, as it too utilizes the Matrix class to implement multiple types of image scaling: https://github.com/yqritc/Android-ScalableImageView

custom made arc shaped seekbar

What I am trying to achieve is to make an arc shaped seekbar. I know there are plenty of libraries I could use to achieve this, but I am just trying my hands on custom made views.
I have encountered couple of problems:
I have a class which extends SeekBar, and I have implemented onDraw and onMeasure methods as well, but I am not able to view that in layout editor in eclipse, here is the code for the custom view class:
package com.custom.android.views;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.PathMeasure;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.SeekBar;
import android.widget.Toast;
public class CustomSeekBar extends SeekBar {
public CustomSeekBar(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public CustomSeekBar(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CustomSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void draw(Canvas canvas) {
// TODO Auto-generated method stub
super.draw(canvas);
}
#Override
protected synchronized void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
Here is my layout xml :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
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=".MainActivity" >
<com.custom.android.views.CustomSeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/seekBar"/>
</RelativeLayout>
If I use canvas class to draw an arc or any shape, would that be a good starting point?
What exactly is wrong with the eclipse adt and how could I use the onDraw method to give shape to that seekbar?
Drawing a ProgressBar with any shape, is pretty easy. With the SeekBar you have some complexity, since you have to achieve 3 diferent things:
Draw the line
Draw the draggable thumb, if you want.
Handle the user interaction
You have to think of it as an arc that is draw inside a rectangle. So point 3 could be easy: just let the user move the finger in a horizontal line, or exactly over the arc, but considering only the x coordinate of the touch event. What does this mean, in short? ok, good news: you dont have to do anything, since thats the normal behavior of the base SeekBar.
For the second point, you can choose an image for the handler, and write it in the corresponding position with a little maths. Or you can forget the handler for know, and just draw the seek bar as a line representing the full track, and another line over it representing the progress. When you have this working, if you want you can add the handler.
And for the first point, this is the main one, but its not hard to achieve. You can use this code:
UPDATE: I made some improvements in the code
public class ArcSeekBar extends SeekBar {
public ArcSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ArcSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
private Paint mBasePaint;
private Paint mProgressPaint;
private RectF mOval = new RectF(5, 5, 550, 550);
private int defaultmax = 180;
private int startAngle=180;
private int strokeWidth=10;
private int trackColor=0xFF000000;
private int progressColor=0xFFFF0000;
public void setOval(RectF mOval) {
this.mOval = mOval;
}
public void setStartAngle(int startAngle) {
this.startAngle = startAngle;
}
public void setStrokeWidth(int strokeWidth) {
this.strokeWidth = strokeWidth;
}
public void setTrackColor(int trackColor) {
this.trackColor = trackColor;
}
public void setProgressColor(int progressColor) {
this.progressColor = progressColor;
}
public ArcSeekBar(Context context) {
super(context);
mBasePaint = new Paint();
mBasePaint.setAntiAlias(true);
mBasePaint.setColor(trackColor);
mBasePaint.setStrokeWidth(strokeWidth);
mBasePaint.setStyle(Paint.Style.STROKE);
mProgressPaint = new Paint();
mProgressPaint.setAntiAlias(true);
mProgressPaint.setColor(progressColor);
mProgressPaint.setStrokeWidth(strokeWidth);
mProgressPaint.setStyle(Paint.Style.STROKE);
setMax(defaultmax);// degrees
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawArc(mOval, startAngle, getMax(), false, mBasePaint);
canvas.drawArc(mOval, startAngle, getProgress(), false, mProgressPaint);
invalidate();
//Log.i("ARC", getProgress()+"/"+getMax());
}
}
Of course, you can and you should make everything configurable, be means of the contructor, or with some setters for the start and end angles, dimensions of the containing rectangle, stroke widths, colors, etc.
Also, note that the arc is drawn from 0 to getProgress, being this number an angle relative to the x axis, growing clocwise, so, if it go from 0 to 90 degrees, it will be something like:
Of course you can change this: canvas.drawArc get any number as an angle, and it is NOT treated as module 360, but you can do the maths and have it starting and ending in any point you want.
In my example the beggining is in the 9 of a clock, and it takes 180 degrees, to the 3 in the clock.
UPDATE
I uploaded a running example to github

Mirror (flip) a View / ProgressBar

I have a custom built circular progress bar used for a seconds counter on a clock, which I'd like to flip, so that the clock is counting counter-clockwise.
Searching here for a solution, I found this:
Right to Left ProgressBar?
Which obviously works for a horizontal progress bar, but I can't simply rotate it 180 degrees, since that will just move the clock 180 degrees and it will still be ticking clockwise.
Is there any other way to mirror a ProgressBar, or any View?
Edit:
Just found "android:rotationY" and the programmatic equivalent, but this ideally needs to be for 2.2 and above..
I was able to flip ProgressBar simply with attribute scaleX in XML:
android:scaleX="-1"
This works for other View as well.
Extend ProgressBar in the same way you would for a horizontal progress bar, but in the onDraw method, flip the canvas rather than rotate it:
public class InverseProgressBar extends ProgressBar {
public InverseProgressBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public InverseProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public InverseProgressBar(Context context) {
super(context);
}
#Override
protected synchronized void onDraw(Canvas canvas) {
canvas.scale(-1f, 1f, super.getWidth() * 0.5f, super.getHeight() * 0.5f);
super.onDraw(canvas);
}
}
Yes. In newer versions of material design library, the circular progress bar can be mirrored:
in the layout with this attribute
app:indicatorDirectionCircular
or programmatically with this method
setIndicatorDirection()
Refer here for more info.

Skewing a text view in Android

I'm looking to replicate the following within my application:
As you can see, its basically a button which increases/decreases the value of the text view contained within it. This button will have three visual states -> unpressed, decrease and increase (as seen in the image above, the user taps the increase arrows and the button appears pressed in on that side)
Here are my 3 button states currently:
As you can see, the problem I have is being able to correctly skew/rotate the text view so it looks visually correct and appears slanted along with the button when its being increased or decreased.
I have tried two different approaches so far:
Create a custom text view class which overrides the onDraw() method to skew the canvas:
#Override
public void onDraw(Canvas canvas) {
canvas.save();
canvas.skew(0.2f, 0f);
super.onDraw(canvas);
canvas.restore();
}
Integrate the Rotate3dAnimation class (source here) and used many different variations to get the desired result such as:
Rotate3dAnimation skew = new Rotate3dAnimation(
30, 0, centerX, centerY, 0, false);
txtAmount.startAnimation(skew);
Unfortunately, I'm not quite getting the exact result that mirrors the first image above. I'm getting confused with setting values with the Z-axis, skew, rotate etc.
I'd greatly appreciate any help from anyone who has experience with this stuff. Thanks in advance
Well I even tried and I came up with something like this:
public class DemoActivity extends TextView {
Context context;
String firstText = "$120.00";
public DemoActivity(Context context)
{
super(context);
this.context = context;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
setText(firstText);
setTextSize(30);
canvas.skew(1.0f, 0.3f); //you need to change values over here
Rotate3dAnimation skew = new Rotate3dAnimation(
-20, 30,200, 200, 0, false); //here too
startAnimation(skew);
}
}
I got an output as:
I guess changing the values by trial and error can solve your problem.
Hope it helps.
Thanks to Parth Doshi answer. His answer need a little tweaking to run which I'm sharing here to save someone else time.
First create a class in src folder and write all of three constructors.
public class TextViewDemo extends TextView {
Context context;
String text = "TESTING 3DX TOOLS";
public TextViewDemo(Context context) {
super(context);
this.context = context;
}
public TextViewDemo(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public TextViewDemo(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
setText(text);
setTextSize(30);
canvas.skew(0.5f, 1.0f); // you need to change values over here
Rotate3dAnimation skew = new Rotate3dAnimation(-50, 30, 0, 0, 0,
false); // here too
startAnimation(skew);
}
}
In you res/layout/my_layout.xml file you can add a tag of your custom made TextView.
<com.yourpackage.name.TextViewDemo
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="Hello World"
<!-- All parameters and value shall remain same -->
/>
Like any other view, you can create an instance of TextViewDemo in your onCreate() method
TextViewDemo txtDemo = (TextViewDemo) findViewById(R.id.name);
Regards

Is it possible to change the RatingBar direction?

Does anyone knows if its possible to make the RatingBar go from right-to-Left instead of left to right, or have an idea how to do it?
You can use android:rotation="180" in your Ratingbar to rotate it
i used this way on my read-only Ratingbars, i dont know if this will effect interacting with the Ratingbar.
Use attribute android:scaleX="-1"
OR
package com.example.selection;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RatingBar;
public class InvertRatingBar extends RatingBar {
public InvertRatingBar(Context context) {
super(context);
}
public InvertRatingBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public InvertRatingBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int width = this.getMeasuredWidth();
event.setLocation(width - event.getX(), event.getY());
return super.onTouchEvent(event);
}
#Override
protected synchronized void onDraw(Canvas canvas) {
int width = this.getMeasuredWidth();
Matrix matrix = canvas.getMatrix();
matrix.preTranslate(width, 0);
matrix.preScale(-1.f, 1);
canvas.setMatrix(matrix);
super.onDraw(canvas);
}
}
You have to customize the RatingBar..
However you just have to play tricks with displaying RatingBar Images & then some sort of reverse calculations.
Trick will be displaying reverse Images in RatingBar.. swap selected and unselected images in RatingBar.
Allow user to rate on RatingBar. You have to swap selected and unselected calculations. I mean you have to do reverse calculations.
Complete Working example of custom RatingBar on StackOverflow answered by me only.
Download RatingBar icons from here : http://developer.android.com/guide/practices/ui_guidelines/icon_design.html

Categories

Resources