I'm currently programming in Monodroid and I'm having an issue with the extension of a Listview.
I currently have ListView extended like this:
public class TTListView : ListView
{
private Context mContext;
private bool wrapAdapter;
public TTListView(Context context) :
base(context)
{
Initialize();
this.mContext = context;
}
public TTListView(Context context, IAttributeSet attrs) :
base(context, attrs)
{
Initialize();
this.mContext = context;
}
public TTListView(Context context, IAttributeSet attrs, int defStyle) :
base(context, attrs, defStyle)
{
Initialize();
this.mContext = context;
}
private void Initialize()
{
this.CacheColorHint = Color.Transparent;
//Still some more stuff to be added here
}
public void InsertItemAt(int index)
{
Animation anim = AnimationUtils.LoadAnimation(
mContext, Resource.Animator.slide_top_down);
anim.Duration = 500;
this.GetChildAt(index).StartAnimation(anim);
}
public void SetDelegate(TTListDelegate _delegate)
{
this.OnItemClickListener = (IOnItemClickListener)_delegate;
this.OnItemLongClickListener = (IOnItemLongClickListener)_delegate;
}
public override void AddFooterView(View v)
{
base.AddFooterView(v);
wrapAdapter = true;
}
/*public override IListAdapter Adapter
{
get
{
return base.Adapter;
}
set
{
//Check if the passed parameter is a TTListAdapter
TTListAdapter _ttadapter = value as TTListAdapter;
if (_ttadapter != null)
{
_ttadapter.Wrapped = wrapAdapter;
}
base.Adapter = value;
}
}*/
}
The above code works perfectly fine.
The problem with this is when I'm trying to override the Adapter property (which is now commented out) I get the following exception when trying to create a TTListView object:
"Unable to activate instance of type TimeTellApp.TTListView from native handle 40557188. No constructor found for TTListView::.ctor(System.IntPtr, Android.Runtime.JniHandleOwner)"
Usually this has something to do with the GC destroying the managed mapped object so up until now I solved these kind of problems by keeping a reference to the object. The problem with the TTListView is that the exception already comes up when calling the constructor for initialization.
I create a TTListView object like this:
TTListView setting_listview = new TTListView(this);
(Where this is a Activity)
What could be the problem here and what would be the best way to solve it?
The error message says that you're missing a specific constructor in your class, which you should implement:
protected ListView (IntPtr javaReference, Android.Runtime.JniHandleOwnership transfer)
Related
I have implement a checkable CardView by following https://medium.com/#AlbinPoignot/checkable-cardview-in-all-android-versions-7124ca6df1ab
However, I need to let the user select just one option.
To clarify, if one is already checked, and the user select other, I need to deselect the previous option.
Furthermore, I need to when return the selected CardView keeps the checked state.
Could someone help me with this 2 tasks? Below is my implementation:
public class CheckableCardView extends CardView implements Checkable {
private static final int[] CHECKED_STATE_SET = {
android.R.attr.state_checked
};
private boolean isChecked;
private TextView itemText;
public CheckableCardView(Context context) {
super(context);
init(null);
}
public CheckableCardView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public CheckableCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet attrs) {
LayoutInflater.from(getContext()).inflate(R.layout.checkable_card_view, this, true);
setClickable(true);
setChecked(false);
setCardBackgroundColor(ContextCompat.getColorStateList(getContext(), R.color.selector_card_view_background));
if (attrs != null) {
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.CheckableCardView, 0, 0);
try {
String text = ta.getString(R.styleable.CheckableCardView_card_text);
itemText = (TextView) findViewById(R.id.text);
if (text != null) {
setText(text);
}
} finally {
ta.recycle();
}
}
}
public void setText(String text){
itemText.setText(text);
}
#Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
#Override
public boolean performClick() {
toggle();
return super.performClick();
}
#Override
public void setChecked(boolean checked) {
this.isChecked = checked;
}
#Override
public boolean isChecked() {
return isChecked;
}
#Override
public void toggle() {
setChecked(!this.isChecked);
}
}
You can also use the MaterialCard provided by the Material Components Library.
This card implement a Checkable interface by default.
Just use the android:checkable attribute in the xml:
<com.google.android.material.card.MaterialCardView
android:checkable="true"
..>
or setCheckable(true) in your code.
A way of switching to checked state is:
final MaterialCardView cardView = findViewById(R.id.card);
cardView.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) {
//cardView.setChecked(!cardView.isChecked());
cardView.toggle();
}
});
For those who are looking for an easy solution to this problem, here is the code:
cardONE.setOnClickListener {
cardONE.isChecked = true // set the current card to checked
cardTWO.isChecked = false // set the other card to unchecked
}
cardTWO.setOnClickListener {
cardTWO.isChecked = true
cardONE.isChecked = false
}
Or the function:
fun setChecked(checkCard: MaterialCardView, uncheckCard: MaterialCardView){
checkCard.isChecked = true
uncheckCard.isChecked = false
}
cardONE.setOnClickListener {
setChecked(it as MaterialCardView, cardTWO)
}
It's maybe not the most "elegant" way, but it works like a charm.
Needed Dependencies
implementation "com.google.android.material:material:1.2.0"
XML File
<com.google.android.material.card.MaterialCardView
android:id="#+id/cardONE"
<!-- THIS IS NEEDED -->
android:checkable="true"
android:clickable="true"
android:focusable="true" />
You can do that by declare:
private List<CheckableCardView> checkableCardViewList = new ArrayList<>();
then you can add your cards to your list in "onBindViewHolder"
checkableCardViewList.add(position,holder.cardView);
finally you can add a callback function like "onClick"
holder.cardView.setOnClickListener(new CheckableCardView.OnClickListener() {
#Override
public void onClick(boolean b) {
if (b) {
for(CheckableCardView checkableCardView : checkableCardViewList) {
checkableCardView.setChecked(false);
}
checkableCardViewList.get(position).setChecked(true);
notifyDataSetChanged();
}
}
});
for call back you can add this to your CheckableCardView at bottom
public void setOnClickListener(OnClickListener onClickListener) { this.onClickListener = onClickListener;}
public interface OnClickListener {
void onClick(boolean b);
}
and at the top
private OnClickListener onClickListener;
#Override
public boolean performClick() {
toggle();
onClickListener.onClick(this.isChecked);
return super.performClick();
}
I have a extended EditText and I can not call any standard function with the following situation:
MainActivity
private Editor sEditor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ex);
sEditor = (Editor)findViewById(R.id.s_editor);
}
private String retText() {
return sEditor.getText.toString();
}
Editor
public Editor(Context context) {
super(context);
init();
}
public Editor(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Editor(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
}
When retText() is called:
Attempt to invoke virtual method 'android.text.Editable com.paulo.ex.Editor.getText()' on a null object reference
I also tried to initialize Editor as sEditor = new Editor(MainActivity.this); but the return value of retText() is always null. What is the appropriate way to resolve this problem?
In my android app I have a list of user's items.
Using a custom adapter to display them, overriding the GetView method.
From a book I got the WebImageView to lazy load images and customized it a bit.
The problem is that when I open the list view and scroll up and down, images get mixed up constantly
Here is some code:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.item_adapterable_my_profile_item, parent, false);
}
iMyItemsFeedItemImage = (ImageWebView) convertView.findViewById(R.id.iMyItemsFeedItemImage);
tvMyItemsFeedItemName = (TextView) convertView.findViewById(R.id.tvMyItemsFeedItemName);
tvMyItemsFeedItemName.setText(itemNames.get(position));
iMyItemsFeedItemImage.setPlaceholderImage(R.drawable.images_default_product);
iMyItemsFeedItemImage.setVisibility(View.VISIBLE);
iMyItemsFeedItemImage.setImageUrl(C.API.WEB_ADDRESS + C.API.IMAGES_ITEMS_FOLDER_THUMBNAIL + itemImages.get(position));
return convertView;
} // End of getView
and the ImageWebView class:
public class ImageWebView extends ImageView implements OnDownloadImageListener {
private Drawable mPlaceholder;
private Drawable mImage;
private Bitmap cachedBitmap;
private boolean imageBitmapCached = false;
public ImageWebView(Context context) {
this(context, null);
}
public ImageWebView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ImageWebView(Context context, AttributeSet attrs, int defaultStyle) {
super(context, attrs, defaultStyle);
}
public void setPlaceholderImage(Drawable drawable) {
mPlaceholder = drawable;
if (mImage == null) {
setImageDrawable(mPlaceholder);
}
}
public void setPlaceholderImage(int resid) {
mPlaceholder = getResources().getDrawable(resid);
if (mImage == null) {
setImageDrawable(mPlaceholder);
}
}
public void setImageUrl(String url) {
if (imageBitmapCached) {
setImageBitmap(cachedBitmap);
} else {
new DownloadImage(this, url).execute();
}
}
#Override
public void onDownloadImageSuccess(Bitmap image) {
setImageBitmap(image);
cachedBitmap = image;
imageBitmapCached = true;
}
#Override
public void onDownloadImageFailure() {
};
} // End of Class
The names remain the same, in the same order that they've been initially, but the images get mixed up
The ListView is recycling views, which means that once you scroll down, the download you triggered for a list item might not apply anymore, because that same list item view has been used to display an item at the bottom of the list, which should have a different image.
What you need to do, is set the URL of the image as a tag to your ImageWebView in your setImageUrl method, and then in onImageDownloaded, check if the Url in the tag is still the same as the one you just downloaded. If it's not, it means that your ImageWebView is already being used for a new list item, and you shouldn't set the image. For that you should also add the downloaded image Url as a parameter to your onImageDownloaded method. So the complete solution is:
public void setImageUrl(String url) {
setTag(url);
if (imageBitmapCached) {
setImageBitmap(cachedBitmap);
} else {
new DownloadImage(this, url).execute();
}
}
#Override
public void onDownloadImageSuccess(Bitmap image, String url) {
if(url.equals.((String) getTag())){
setImageBitmap(image);
cachedBitmap = image;
imageBitmapCached = true;
}
}
EDIT:
I would change your entire ImageWebView class like this:
public class ImageWebView extends ImageView implements OnDownloadImageListener {
public ImageWebView(Context context) {
this(context, null);
}
public ImageWebView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ImageWebView(Context context, AttributeSet attrs, int defaultStyle) {
super(context, attrs, defaultStyle);
}
public void setImageUrl(String url, int placeholderResId) {
String oldUrl = (String) getTag();
setTag(url);
if (!url.equals(oldUrl)) {
setImageResource(placeholderResId);
new DownloadImage(this, url).execute();
}
}
#Override
public void onDownloadImageSuccess(Bitmap image, String url) {
if(url.equals((String) getTag())){
setImageBitmap(image);
}
}
And in your adapter, just don't call setPlaceholderImage, simply call the new version of setImageUrl. with the placeholder resource id:
iMyItemsFeedItemImage.setImageUrl(C.API.WEB_ADDRESS + C.API.IMAGES_ITEMS_FOLDER_THUMBNAIL + itemImages.get(position), R.drawable.images_default_product);
You should use shutterbug library to to display images from Url. Its easy n effective.
I have a widget View as below:
public class RemoteNumView extends FrameLayout {
how call I use Roboguice just as in RoboActivity? As below:
#InjectView(R.id.btn_remote_control_num_0)
private TextView mText;
Full code is:
/**
* Created by bbcv on 13-12-12.
*/
public class RemoteNumView extends FrameLayout {
private IService mService;
#InjectView(R.id.btn_remote_control_num_0)
private TextView mText;
public RemoteNumView(Context context) {
super(context);
///
addView(LayoutInflater.from(context).inflate(R.layout.v_remote_control_fun,null));
}
public RemoteNumView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RemoteNumView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setService(IService service){
mService = service;
}
}
Anyone can HELP?
Solved it by writing custom code. Roboguice is badly written for this purpose.
protected void injectViews() {
for (Field field : this.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(InjectView.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new UnsupportedOperationException("Views can't be staticaly assigned.");
} else {
if (View.class.isAssignableFrom(field.getType())) {
try {
final InjectView injectView = field.getAnnotation(InjectView.class);
;
final int id = injectView.value();
View view = findViewById(id);
if ((view == null) && Nullable.notNullable(field)) {
throw new NullPointerException(String.format("Can't inject null value into %s.%s when field is not #Nullable", field.getDeclaringClass(), field.getName()));
}
field.setAccessible(true);
field.set(this, view);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
} else {
throw new UnsupportedOperationException("Need view type to assign");
}
}
}
}
I am new in android and I want use my custom font for my app. I wrote 2 ways creating custom font. Could you tell me guys which one is better and faster.
first way is using singleton class second way is create my own textview.
with singleton
public class FontFactory {
private static FontFactory instance;
private HashMap<String, Typeface> fontMap = new HashMap<String, Typeface>();
private FontFactory() {
}
public static FontFactory getInstance() {
if (instance == null){
instance = new FontFactory();
}
return instance;
}
public Typeface getFont(DefaultActivity pActivity,String font) {
Typeface typeface = fontMap.get(font);
if (typeface == null) {
typeface = Typeface.createFromAsset(pActivity.getResources().getAssets(), "fonts/" + font);
fontMap.put(font, typeface);
}
return typeface;
}
}
with own textview
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setFonts(context,attrs);
}
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setFonts(context,attrs);
}
private void setFonts(Context context, AttributeSet attrs){
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyTextView_customFont);
String ttfName = a.getString(R.styleable.MyTextView_customFont_ttf_name);
setCustomTypeFace(context, ttfName);
}
public void setCustomTypeFace(Context context, String ttfName) {
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/MuseoSansCyrl_"+ttfName+".otf");
setTypeface(font);
}
#Override
public void setTypeface(Typeface tf) {
super.setTypeface(tf);
}
}
In your custom textview approach, you are creating the Typeface object every time you create a CustomTextView (or change its typeface), while your factory would keep the already loaded ones around in memory and re-use them.
The approach with a custom text view may work fine in some instances, but if you suddenly need to create a lot of them (or change the typeface on a lot of them), it might noticably slow down your performance as in this question with a scrollview.
I'd choose the singleton.