Getting resource ID or InputStream from ImageView Drawable - android

I am developing a GifView class, extending android.view.ImageView to show an animation gif in Android.
The problem is getting android:src="#drawable/myGif" from XML layout to load it in Movie automatically. When I override setImageDrawable(Drawable drawable) to intercept default android behaviour, I have two differents ways to do it: getting the id resource from #drawable/myGif and save it for later use, or load it on demand in Movie. But with the latter option I need to convert Drawable in InputStream unused compress method from Bitmap class to can safe GIF layers.
How can I do it?
public class GifView extends ImageView {
...
private Movie movie;
private int resId;
public GifView(Context context) {
super(context);
this.context = context;
}
public GifView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public GifView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
}
#Override
public void setImageDrawable(Drawable drawable) {
// ONE OF THOSE WAYS TO DO
// this.redId = ...
// this.movie = Movie.decodeStream(...);
}
...
}

ok, you can do it automatically, but does it really pay of?
public class GifImageView extends ImageView {
private final static String TAG = "GifImageView";
public GifImageView(Context context, AttributeSet attrs) {
super(context, attrs);
int[] attrArray = {
android.R.attr.src
};
TypedArray a = context.obtainStyledAttributes(attrs, attrArray);
int id = a.getResourceId(0, 0);
a.recycle();
if (id != 0) {
try {
Drawable d = new GifDrawable(getResources(), id);
setImageDrawable(d);
} catch (Exception e) {
Log.d(TAG, "GifImageView " + e.getMessage());
}
}
}
class GifDrawable extends Drawable implements Runnable {
...
}
}

Related

set image dynamically to the custom imageview class android

I want to load the url into ImageView and that url is dynamic, so I created the custom Imageview class like this
public class CustomLocalCurrencyImageViewWhiteColor extends AppCompatImageView {
public CustomLocalCurrencyImageViewWhiteColor(Context context) {
super(context);
Glide.with(context).load(SessionManager.getCountryWiseDataObject(context).getCurrencyImageWhite()).into(this);
}
public CustomLocalCurrencyImageViewWhiteColor(Context context, AttributeSet attrs) {
super(context, attrs);
Glide.with(context).load(SessionManager.getCountryWiseDataObject(context).getCurrencyImageWhite()).into(this);
}
public CustomLocalCurrencyImageViewWhiteColor(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
Glide.with(context).load(SessionManager.getCountryWiseDataObject(context).getCurrencyImageWhite()).into(this);
}
}
.Its working fine when I used it the following way
<com.kiran.example.ebitcoin.customview.CustomLocalCurrencyImageViewWhiteColor
android:id="#+id/img"
android:layout_width="#dimen/imageSizeTooSmallBTCLogo"
android:layout_height="#dimen/imageSizeTooSmallBTCLogo"
android:layout_gravity="center_vertical" />
Now, I want to change the image resource of this custom image too, dynamically, So I tried
CustomLocalCurrencyImageViewWhiteColor img = findViewById(R.id.img);
img.setImageResource(R.drawable.ic_bitcoin_24_white);
But unfortunately, nothing is changed. How to change the image of custom image view class dynamically?? Any one found answer of this?
Finally , I got answer of my own question. I follow this, and done the code by following way.
public class CustomLocalCurrencyImageViewWhiteColor extends AppCompatImageView {
Context context;
public CustomLocalCurrencyImageViewWhiteColor(Context context) {
super(context);
Glide.with(context).load(SessionManager.getCountryWiseDataObject(context).getCurrencyImageWhite()).into(this);
}
public CustomLocalCurrencyImageViewWhiteColor(Context context, AttributeSet attrs) {
super(context, attrs);
Glide.with(context).load(SessionManager.getCountryWiseDataObject(context).getCurrencyImageWhite()).into(this);
}
public CustomLocalCurrencyImageViewWhiteColor(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
Glide.with(context).load(SessionManager.getCountryWiseDataObject(context).getCurrencyImageWhite()).into(this);
}
public void setImageWithGlide(Context context, Integer resId) {
this.context = context;
Glide.with(context).load("").placeholder(resId).into(this);
}
}
To change the image dynamically,
CustomLocalCurrencyImageViewWhiteColor img = findViewById(R.id.img);
img.setImageWithGlide(this, R.drawable.image);
As you are extending AppCompatImageView you can do as following:
Drawable drawable = AppCompatDrawableManager.get().getDrawable(getApplicationContext(), R.drawable.ic_bitcoin_24_white);
img.setImageResource(drawable);
Well u already use Glide in the first place, so try do it this way:
create setImageWithGlide method in CustomLocalCurrencyImageViewWhiteColor
public void setImageWithGlide(Context context, String imagePath) {
Glide.with(context).load(imagePath).into(this)
}
public void setImageWithGlide(Context context, Integer resId) {
Glide.with(context).load(resId).into(this)
}
you can use it like this:
img.setImageWithGlide(imagePath);
or if u use resourceId
img.setImageWithGlide(R.drawable.image);

Custom ImageView performance

I created a custom ImageView - it's purpose is to fetch image from internet. It's declaration looks as below:
public class WebImageView extends ImageView {
private String mUrl;
private Bitmap mCachedBitmap;
public String getUrl() { return mUrl; }
public void setUrl(String url) {
mUrl = url;
if (mCachedImage == null) {
new ImageDownloader(this).execute(mUrl);
} else {
setImageBitmap(mCachedImage);
}
}
public WebImageView(Context context) {
super(context);
}
public WebImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public WebImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public WebImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
private class ImageDownloader extends AsyncTask<String, Void, Bitmap> {
private final ImageView mView;
public ImageDownloader(ImageView view) {
mView = view;
}
#Override
protected Bitmap doInBackground(String... params) {
String url = params[0];
Bitmap image = null;
try {
InputStream in = new java.net.URL(url).openStream();
image = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error Message", e.getMessage());
e.printStackTrace();
}
return image;
}
protected void onPostExecute(Bitmap result) {
mView.setImageBitmap(result);
}
}
}
And it's usage is pretty straightforward:
<com.myapp.views.controls.WebImageView
android:layout_width="#dimen/restaurantLogoWidth"
android:layout_height="#dimen/restaurantLogoHeight"
url="#{restaurant.model.logoUrl}"
style="#style/ImageView" />
The above xml is placed inside a android.support.v7.widget.RecyclerView. The problem is that when I scroll (or perform some animation) on my items list it performs horribly bad, meaning that scrolling (or animating) is not smooth. Any advice what can I change here to make it perform better?
Don't build a custom view to do this. Just use Glide image loading library.
https://github.com/bumptech/glide
ImageView targetImageView = (ImageView) findViewById(R.id.imageView);
String internetUrl = "http://i.imgur.com/DvpvklR.png";
Glide
.with(context)
.load(internetUrl)
.into(targetImageView);
https://futurestud.io/tutorials/glide-getting-started
Recyclerview Adapter and Glide - same image every 4-5 rows

Setting Custom Font for TextView causing the onCreate to take longer to build

I am currently implementing Roboto font within my project. For some fragments, there are a lot of TextView's. I am creating a custom View that exends TextView to implement custom fonts. Is there a better way to load the fonts without increasing the onCreate times?
Extends TextView
public class TextViewFont extends TextView {
public TextViewFont(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
public TextViewFont(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public TextViewFont(Context context) {
super(context);
init(null);
}
private void init(AttributeSet attrs) {
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.TextViewFont);
String fontName = a.getString(R.styleable.TextViewFont_fontName);
if (fontName != null) {
Typeface myTypeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/" + fontName);
setTypeface(myTypeface);
}
a.recycle();
}
}
}
XML
<com.eugene.fithealthmaingit.Custom.TextViewFont
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_weight="1"
android:text="#string/dinner"
android:textColor="#color/text_color"
android:textSize="16sp"
app:fontName="Roboto-Regular.ttf"/>
Example of how many TextView's
This is the library that saved my life Calligraphy. It's really nice and easy to use.
Typeface.createfromassets is a time taking process. You should declare typeface as static varaiable in class and just use it in constructor.
But here you are loading fonts in every textview's constructor.
If you having multiple fonts, have all tytypeface as static and use it appropriately.
UPDATE CODE:
public class TextViewFont extends TextView {
public static Typeface typeface1 = Typeface.createFromAsset(getContext().getAssets(), "fonts/fontName1");
public static Typeface typeface2 = Typeface.createFromAsset(getContext().getAssets(), "fonts/fontName2");
public static Typeface typeface3 = Typeface.createFromAsset(getContext().getAssets(), "fonts/fontName3");
public static Typeface typeface4 = Typeface.createFromAsset(getContext().getAssets(), "fonts/fontName4");
public static Typeface typeface5 = Typeface.createFromAsset(getContext().getAssets(), "fonts/fontName5");
public TextViewFont(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
public TextViewFont(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public TextViewFont(Context context) {
super(context);
init(null);
}
private void init(AttributeSet attrs) {
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.TextViewFont);
String fontName = a.getString(R.styleable.TextViewFont_fontName);
if (fontName != null) {
setTypeface(getTypeFace(fontName));
}
a.recycle();
}
}
public Typeface getTypeFace(String fontName){
if(fontName.equals("fontName1")){
return typeface1;
}else if(fontName.equals("fontName2")){
return typeface2;
}else if(fontName.equals("fontName3")){
return typeface3;
}else if(fontName.equals("fontName4")){
return typeface4;
}else if(fontName.equals("fontName5")){
return typeface5;
}
}
}
}
Try using an instance singleton or applicationsingleton. See if this works. So you can just call TextLover.get(context).getFont(id). It will create and cache it on the fly. This way your other views can also reuse the font cache. eg. buttons
class TextLover {
private static TextLover singleton;
private final Context context;
private final SparseArray<Typeface> faces = new SparseArray<Typeface>();
public TextLover get(Context context) {
if (singleton == null) {
singleton = new TextLover(context);
}
return singleton;
}
private TextLover(Context context) {
this.context = context;
}
private static final String[] fonts = {
"fonts/fontName1",
"fonts/fontName2",
"fonts/fontName3",
"fonts/fontName4",
"fonts/fontName5",
...
"fonts/fontName100"
}
// NOTE you need a mapping of ids to each asset font in fonts[]
public Typeface getFont(int id) {
Typeface font = faces.get(id);
if (font == null) {
font = Typeface.createFromAsset(context.getAssets(), fonts[id]);
faces.append(id, font);
}
return font;
}
}

Where to Set Custom Typeface in Custom View Class (extends Button)?

I have a custom View class that extends Button. I'd like to set a custom Typeface to all instances of this class, but since some methods get called multiple times in a view, I was wondering what is the best overwriting method to place the following code in?
final Typeface face = Typeface.createFromAsset(getContext().getAssets(),
"myfont.ttf");
this.setTypeface(face);
Currently, I have it in onMeasure(), but I noticed it gets called multiple times, which I assume won't be good for performance.
Most correct is to add your code to constructor.
public class ButtonPlus extends Button {
public ButtonPlus(Context context) {
super(context);
}
public ButtonPlus(Context context, AttributeSet attrs) {
super(context, attrs);
setCustomFont(context, attrs);
}
public ButtonPlus(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setCustomFont(context, attrs);
}
private void setCustomFont(Context ctx, AttributeSet attrs) {
TypedArray a = ctx.obtainStyledAttributes(attrs,
R.styleable.TextViewPlus);
String customFont = a.getString(R.styleable.TextViewPlus_customFont);
setCustomFont(ctx, customFont);
a.recycle();
}
public boolean setCustomFont(Context ctx, String asset) {
Typeface tf = null;
try {
tf = Typeface.createFromAsset(ctx.getAssets(), asset);
} catch (Exception e) {
return false;
}
setTypeface(tf);
return true;
}
}
here customFont - is my custom attribute. i specify font from layout using this attr. I just created following custom attr in values/attrs.xml

Performance issue on custom font TextView

I have a custom TextView, with a personalized font attribute:
public class TextViewPlus extends TextView {
private static final String TAG = "TextViewPlus";
public TextViewPlus(Context context) {
super(context);
}
public TextViewPlus(Context context, AttributeSet attrs) {
// This is called all the time I scroll my ListView
// and it make it very slow.
super(context, attrs);
setCustomFont(context, attrs);
}
public TextViewPlus(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setCustomFont(context, attrs);
}
private void setCustomFont(Context ctx, AttributeSet attrs) {
TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.TextViewPlus);
String customFont = a.getString(R.styleable.TextViewPlus_customFont);
setCustomFont(ctx, customFont);
a.recycle();
}
public boolean setCustomFont(Context ctx, String asset) {
Typeface tf = null;
try {
tf = Typeface.createFromAsset(ctx.getAssets(), asset);
setTypeface(tf);
} catch (Exception e) {
Log.e(TAG, "Could not get typeface: "+e.getMessage());
return false;
}
return true;
}
}
I'm using it in my XML files with the attribute customFont="ArialRounded.ttf", and it is working quite well.
I'm using this TextViewPlus in a ListView, populated with an ArrayAdapter.
TextViewPlus dataText = (TextViewPlus) itemView.findViewById(R.id.data_text);
dataText.setText("My data String");
My problem is that the performance, when I'm scrolling the ListView, are terrible! Very slow and full of lags. The TextViewPlus constructor n°2 it's called all the time i scroll the list.
If I change TextViewPlus in a normal TextView, and use dataText.setTypeface(myFont), everything is smood and is working well.
How can I use my TextViewPlus without performance issue?
Why don't you keep the created typface object in memory so that you don't create every time the text view is getting created.
Following is a sample class that creates and cache the typeface object:
public class TypeFaceProvider {
public static final String TYPEFACE_FOLDER = "fonts";
public static final String TYPEFACE_EXTENSION = ".ttf";
private static Hashtable<String, Typeface> sTypeFaces = new Hashtable<String, Typeface>(
4);
public static Typeface getTypeFace(Context context, String fileName) {
Typeface tempTypeface = sTypeFaces.get(fileName);
if (tempTypeface == null) {
String fontPath = new StringBuilder(TYPEFACE_FOLDER).append('/').append(fileName).append(TYPEFACE_EXTENSION).toString();
tempTypeface = Typeface.createFromAsset(context.getAssets(), fontPath);
sTypeFaces.put(fileName, tempTypeface);
}
return tempTypeface;
}
}

Categories

Resources