Custom CheckBox image gets cut off - android

As you can see in the image above. There are three views on this screenshot.
- The first item is CheckBox with text and having state off.
- The second item is CheckBox without text and having state on.
- The last item is ImageView with src pointing to the drawable image.
The CheckBoxes were customized using android:button.
As I tried using smaller images, all of the checkbox is left-aligned.
Comparing these two images tell me that the default size of the CheckBox seems fixed to certain size until text attribute is large enough to require extending.
There is nothing special in the file as well. See following.
custom_cb.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/creditcard_selected" android:state_checked="true" />
<item android:drawable="#drawable/creditcard"/>
</selector>
layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox android:id="#+id/cbFalse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="#drawable/custom_cb"
android:text="" />
<CheckBox android:id="#+id/cbTrue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="#drawable/custom_cb"
android:focusable="false"
android:checked="true"
android:layout_toRightOf="#id/cbFalse" />
<ImageView android:id="#+id/imvTrue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/creditcard"
android:layout_toRightOf="#id/cbTrue" />
</RelativeLayout>
Is there anyway I can use bigger image for CheckBox while keeping the size as wrap_content? If I set CheckBox layout_width to actual pixel or dp then it display full image but that mean I have to manually check for the size every time it change.

Today I had the same problem (my custom image was cutted on the left side).
I fixed it putting:
android:button="#null"
android:background="#drawable/my_custom_checkbox_state.xml"

Just use
android:button="#null"
android:background="#null"
android:drawableLeft="your custom selector"
android:drawablePadding="as you need"
android:text="your text"
Thats it.. Its working fine..

You only have to change your drawable from android:button to android:drawableLeft or android:drawableRight. And set the button to null to not show the default checkbox.
My checkbox looks like this:
<CheckBox
android:id="#+id/cb_toggle_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="#null"
android:drawableLeft="#drawable/livescore_btn_check" />

CheckBox drawables did not work for me at all, android:button and android:background gave completely erratic results and nothing could fix it.
So I wrote my own "custom checkbox".
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import org.apache.commons.lang3.StringUtils;
import butterknife.Bind;
import butterknife.ButterKnife;
import com.example.myapp.R;
/**
* Created by Zhuinden on 2015.12.02..
*/
public class CustomCheckbox
extends LinearLayout
implements View.OnClickListener {
public CustomCheckbox(Context context) {
super(context);
init(null, -1);
}
public CustomCheckbox(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, -1);
}
#TargetApi(11)
public CustomCheckbox(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
#TargetApi(21)
public CustomCheckbox(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs, defStyleAttr);
}
private void init(AttributeSet attributeSet, int defStyle) {
TypedArray a = null;
if(defStyle != -1) {
a = getContext().obtainStyledAttributes(attributeSet, R.styleable.CustomCheckbox, defStyle, 0);
} else {
a = getContext().obtainStyledAttributes(attributeSet, R.styleable.CustomCheckbox);
}
defImageRes = a.getResourceId(0, 0);
checkedImageRes = a.getResourceId(1, 0);
checked = a.getBoolean(2, false);
typeface = a.getString(3);
if(StringUtils.isEmpty(typeface)) {
typeface = "Oswald-Book.otf";
}
text = a.getString(4);
inactiveTextcolor = a.getInteger(5, android.R.color.black);
activeTextcolor = a.getInteger(6, android.R.color.red);
textsize = a.getDimensionPixelSize(7, 0);
a.recycle();
setOnClickListener(this);
if(!isInEditMode()) {
LayoutInflater.from(getContext()).inflate(R.layout.view_custom_checkbox, this, true);
ButterKnife.bind(this);
imageView.setImageResource(checked ? checkedImageRes : defImageRes);
typefaceTextView.setTypeface(typeface);
if(!StringUtils.isEmpty(text)) {
typefaceTextView.setText(text);
}
if(textsize != 0) {
typefaceTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textsize);
} else {
typefaceTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12);
}
}
}
boolean checked;
int defImageRes;
int checkedImageRes;
String typeface;
String text;
int inactiveTextcolor;
int activeTextcolor;
int textsize;
OnCheckedChangeListener onCheckedChangeListener;
#Bind(R.id.custom_checkbox_imageview)
ImageView imageView;
#Bind(R.id.custom_checkbox_text)
TypefaceTextView typefaceTextView;
#Override
protected void onFinishInflate() {
super.onFinishInflate();
}
#Override
public void onClick(View v) {
checked = !checked;
imageView.setImageResource(checked ? checkedImageRes : defImageRes);
typefaceTextView.setTextColor(checked ? activeTextcolor : inactiveTextcolor);
onCheckedChangeListener.onCheckedChanged(this, checked);
}
public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
this.onCheckedChangeListener = onCheckedChangeListener;
}
public static interface OnCheckedChangeListener {
void onCheckedChanged(View buttonView, boolean isChecked);
}
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
imageView.setImageResource(checked ? checkedImageRes : defImageRes);
typefaceTextView.setTextColor(checked ? activeTextcolor : inactiveTextcolor);
}
public void setTextColor(int color) {
typefaceTextView.setTextColor(color);
}
#Override
public Parcelable onSaveInstanceState() {
//begin boilerplate code that allows parent classes to save state
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
//end
ss.checked = this.checked;
ss.defImageRes = this.defImageRes;
ss.checkedImageRes = this.checkedImageRes;
ss.typeface = this.typeface;
ss.text = this.text;
ss.inactiveTextcolor = this.inactiveTextcolor;
ss.activeTextcolor = this.activeTextcolor;
ss.textsize = this.textsize;
return ss;
}
#Override
public void onRestoreInstanceState(Parcelable state) {
//begin boilerplate code so parent classes can restore state
if(!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
//end
this.checked = ss.checked;
this.defImageRes = ss.defImageRes;
this.checkedImageRes = ss.checkedImageRes;
this.typeface = ss.typeface;
this.text = ss.text;
this.inactiveTextcolor = ss.inactiveTextcolor;
this.activeTextcolor = ss.activeTextcolor;
this.textsize = ss.textsize;
}
static class SavedState
extends BaseSavedState {
boolean checked;
int defImageRes;
int checkedImageRes;
String typeface;
String text;
int inactiveTextcolor;
int activeTextcolor;
int textsize;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
this.checked = in.readByte() > 0;
this.defImageRes = in.readInt();
this.checkedImageRes = in.readInt();
this.typeface = in.readString();
this.text = in.readString();
this.inactiveTextcolor = in.readInt();
this.activeTextcolor = in.readInt();
this.textsize = in.readInt();
}
#Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeByte(this.checked ? (byte) 0x01 : (byte) 0x00);
out.writeInt(this.defImageRes);
out.writeInt(this.checkedImageRes);
out.writeString(this.typeface);
out.writeString(this.text);
out.writeInt(this.inactiveTextcolor);
out.writeInt(this.activeTextcolor);
out.writeInt(this.textsize);
}
//required field that makes Parcelables from a Parcel
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
Using the following attrs.xml
<resources
<declare-styleable name="CustomCheckbox">
<attr name="default_img" format="integer"/>
<attr name="checked_img" format="integer"/>
<attr name="checked" format="boolean"/>
<attr name="chx_typeface" format="string"/>
<attr name="text" format="string"/>
<attr name="inactive_textcolor" format="integer"/>
<attr name="active_textcolor" format="integer"/>
<attr name="textsize" format="dimension"/>
</declare-styleable>
</resources>
With following view_custom_checkbox.xml layout:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="#+id/custom_checkbox_imageview"
android:layout_width="#dimen/_15sdp"
android:layout_height="#dimen/_15sdp"
/>
<com.example.TypefaceTextView
android:id="#+id/custom_checkbox_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</merge>
And example:
<com.example.CustomCheckbox
android:id="#+id/program_info_record_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:clickable="true"
android:gravity="center"
app:default_img="#drawable/ic_recording_off"
app:checked_img="#drawable/ic_recording_on"
app:text="#string/record"
app:inactive_textcolor="#color/program_info_buttons_inactive"
app:active_textcolor="#color/active_color"
app:textsize="#dimen/programInfoButtonTextSize"
app:chx_typeface="SomeTypeface.otf"/>
Modify where necessary.

Try using a Linearlayout with horizontal orientation instead of RelativeLayout.Also use weight in every layout to force views to use same width.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox android:id="#+id/cbFalse"
android:weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:button="#drawable/custom_cb"
android:text="" />
<CheckBox android:id="#+id/cbTrue"
android:weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:button="#drawable/custom_cb"
android:focusable="false"
android:checked="true"
android:layout_toRightOf="#id/cbFalse" />
<ImageView android:id="#+id/imvTrue"
android:weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/creditcard"
android:layout_toRightOf="#id/cbTrue" />

Maybe it will be useful to someone, setting gravity attribute to center helped me to avoid image cropping:
<CheckBox
android:id="#+id/cb_accept_agreement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:button="#drawable/checkbox_selector"/>

Related

Android - Custom EditText with different input types

I'm trying to make a custom EditText for currency which means I need to have a prefix of it for the currency and I have to limit users' input to numbers only.
This is my custom EditText code
public OpenSansEditText(Context context, AttributeSet attrs) {
super(context, attrs);
paint = getPaint();
applyCustomFont(context, attrs);
}
public OpenSansEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
paint = getPaint();
applyCustomFont(context, attrs);
}
private void applyCustomFont(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.OpenSansET);
...
// Prefix
String prefix = a.getString(R.styleable.OpenSansET_prefix);
if (prefix != null) {
mPrefix = prefix;
} else {
mPrefix = "";
}
// Prefix Color
int prefixColor = a.getColor(R.styleable.OpenSansET_prefixColor, 0);
if (prefix != null) {
mPrefixColor = prefixColor;
} else {
mPrefixColor = ContextCompat.getColor(context, R.color.miBlack);
}
a.recycle();
}
...
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!mPrefix.equals("")) {
getPaint().getTextBounds(mPrefix, 0, mPrefix.length(), mPrefixRect);
mPrefixRect.right += getPaint().measureText(" "); // add some offset
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!mPrefix.equals("")) {
paint.setColor(mPrefixColor);
canvas.drawText(mPrefix, super.getCompoundPaddingLeft(), getBaseline(), paint);
}
}
#Override
public int getCompoundPaddingLeft() {
return mPrefix.equals("") ? super.getCompoundPaddingLeft()
: super.getCompoundPaddingLeft() + mPrefixRect.width();
}
This is how I use it in xml :
<com.asta.www.classes.OpenSansEditText
android:id="#+id/shopping_filter_priceMinRange"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.4"
android:gravity="center"
android:hint="#string/min"
android:textColor="#color/miBlack"
android:textColorHint="#color/miGrey"
app:prefix="$"
app:prefixColor="#color/miBlack" />
<com.asta.www.classes.OpenSansEditText
android:id="#+id/shopping_filter_priceMaxRange"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.4"
android:gravity="center"
android:hint="#string/max"
android:inputType="number"
android:textColorHint="#color/miGrey"
app:prefix="$"
app:prefixColor="#color/miBlack" />
Which yields :
Only the first one without inputType as number has the currency sign shown, whereas the second ET doesn't have its currency sign shown.
How to achieve currency prefix as text and still keeping inputType to numbers only for user? And I don't want to use two views, namely EditText and TextView to left of it, both inside a ViewGroup to achieve that.
For this type of scenarios I use Compound views. Please see below code for more information.
First create a layout for your custom view like below.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/txt_prefix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="$" />
<EditText
android:id="#+id/et_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="number" />
</LinearLayout>
Now create a new class which should extends the LinearLayout. See below code.
public class OpenSansEditText extends LinearLayout {
private TextView txtPrefix;
private EditText etValue;
private String prefix = "$";
private int prefixColor = Color.BLACK;
public OpenSansEditText(Context context) {
super(context);
initializeViews(context, null);
}
public OpenSansEditText(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
initializeViews(context, attrs);
}
public OpenSansEditText(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initializeViews(context, attrs);
}
private void initializeViews(Context context, AttributeSet attrs) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.opensansedittext_view, this,true);
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.OpenSansEditText);
prefix = a.getString(R.styleable.OpenSansEditText_prefix);
prefixColor = a.getColor(R.styleable.OpenSansEditText_prefixColor, Color.BLACK);
}
}
public CharSequence getValue(){
return etValue.getText();
}
public CharSequence getPrefix(){
return txtPrefix.getText();
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
txtPrefix = (TextView) findViewById(R.id.txt_prefix);
etValue = (EditText) findViewById(R.id.et_value);
txtPrefix.setText(prefix);
txtPrefix.setTextColor(prefixColor);
}
}
And then add your attributes to attribute xml file Ex: (attrs.xml in my case)
<resources>
<declare-styleable name="OpenSansEditText">
<attr name="prefix" format="string"/>
<attr name="prefixColor" format="color"/>
</declare-styleable>
</resources>
Now you can use it anywhere in the project as below
<com.asta.www.classes.OpenSansEditText
android:layout_width="match_parent"
android:layout_height="match_parent"
app:prefix="$"
app:prefixColor="#f00"/>
Hope this will help you to solve your problem. Thanks...
In the end I found this link https://gist.github.com/kennydude/5407963 which helps me in the right direction. So what it does is I think making the prefix as Drawable using this class :
private class TagDrawable extends Drawable {
public String text = "";
public void setText(String s){
text = s;
// Tell it we need to be as big as we want to be!
setBounds(0,0,getIntrinsicWidth(),getIntrinsicHeight());
invalidateSelf();
}
#Override
public void draw(#NonNull Canvas canvas) {
// I don't know why this y works here, but it does :)
// (aka if you are from Google/are Jake Wharton and I have done it wrong, please tell me!)
canvas.drawText( text, 0, mLine0Baseline + canvas.getClipBounds().top, mTextPaint );
}
#Override public void setAlpha(int i) {}
#Override public void setColorFilter(ColorFilter colorFilter) {}
#Override public int getOpacity() {return PixelFormat.UNKNOWN;}
#Override public int getIntrinsicHeight (){
return (int)mFontHeight;
}
#Override public int getIntrinsicWidth(){
return (int)mTextPaint.measureText( text );
}
}
And draw it to the left of the TextView like
TagDrawable left = new TagDrawable();
left.setText("$");
setCompoundDrawablesRelative(left, null, null, null);
The link I supplied even has suffix support which I haven't tried.

How to auto-adjust image height used as a drawable item in a layer-list?

I have a custom image of a RatingBar and I wanted to auto-adjust the image height depending on the space left from the parent layouts.
Here's the layout:
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/rateus_bg"
android:scaleType="fitXY" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.ims.westmont.android.view.TextViewUniSans
android:id="#+id/textview_rate_us"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="#string/rate_us"
android:textAllCaps="true"
android:textColor="#android:color/white"
android:textSize="60sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<RatingBar
android:id="#+id/ratingbar_rate"
style="#style/rateUsBar"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:numStars="5"
android:rating="0"
android:stepSize="0.5" />
</LinearLayout>
<com.ims.westmont.android.view.TextViewUniSans
android:id="#+id/button_send"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/send"
android:textColor="#android:color/white"
android:textSize="60sp"
android:textAllCaps="true"
android:layout_weight="1"
android:gravity="center"/>
</LinearLayout>
Here's the visual representation:
Since I am using a LinearLayout, the three elements in it have equal height. The RatingBar uses a custom style:
<style name="rateUsBar" parent="#android:style/Widget.RatingBar">
<item name="android:progressDrawable">#drawable/rating_stars</item>
<item name="android:minHeight">90dp</item>
<item name="android:maxHeight">90dp</item>
</style>
And finally the drawable rating_stars:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#android:id/background"
android:drawable="#drawable/rate_empty" />
<item
android:id="#android:id/secondaryProgress"
android:drawable="#drawable/rate_empty" />
<item
android:id="#android:id/progress"
android:drawable="#drawable/rate_filled" />
</layer-list>
Is this a weight issue or should I create a custom view (class) to adjust height?
One solution is
Use Different Values folder
values
2.values-mdpi, values-mdpi-land 3 values-sw320dp, values-sw320dp-land 4 values-sw480dp, values-sw480dp-land 5 values-sw600dp, values-sw600dp-land 6 values-sw720dp, values-sw720dp-land
Now put your style.xml file on each of this folder and according to your device set the height and width respectively.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<RatingBar
android:id="#+id/ratingbar_rate"
style="#style/rateUsBar"
android:numStars="5"
android:rating="0"
android:stepSize="0.5" />
</LinearLayout>
You can check preview your layout for different device in preview option.
if you get any problem using below code let me know.
By following below code you will be able to set the height and width with any value :)
put it inside customratingbar.java
package com.example.ashis.myapplication;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.example.ashis.myapplication.R;
/**
* Created by poliveira on 07/08/2014.
*/
/**
* regular rating bar. it wraps the stars making its size fit the parent
*/
public class customratingbar extends LinearLayout {
public IRatingBarCallbacks getOnScoreChanged() {
return onScoreChanged;
}
public void setOnScoreChanged(IRatingBarCallbacks onScoreChanged) {
this.onScoreChanged = onScoreChanged;
}
public interface IRatingBarCallbacks {
void scoreChanged(float score);
}
private int mMaxStars = 5;
private float mCurrentScore = 2.5f;
private int mStarOnResource = R.mipmap.stars;
private int mStarOffResource = R.mipmap.ic_launcheroff;
private int mStarHalfResource = R.mipmap.stars;
private ImageView[] mStarsViews;
private float mStarPadding;
private IRatingBarCallbacks onScoreChanged;
private int mLastStarId;
private boolean mOnlyForDisplay;
private double mLastX;
private boolean mHalfStars = true;
public customratingbar(Context context) {
super(context);
init();
}
public float getScore() {
return mCurrentScore;
}
public void setScore(float score) {
score = Math.round(score * 2) / 2.0f;
if (!mHalfStars)
score = Math.round(score);
mCurrentScore = score;
refreshStars();
}
public void setScrollToSelect(boolean enabled) {
mOnlyForDisplay = !enabled;
}
public customratingbar(Context context, AttributeSet attrs) {
super(context, attrs);
initializeAttributes(attrs, context);
init();
}
private void initializeAttributes(AttributeSet attrs, Context context) {
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CustomRatingBar);
final int N = a.getIndexCount();
for (int i = 0; i < N; ++i) {
int attr = a.getIndex(i);
if (attr == R.styleable.CustomRatingBar_maxStars)
mMaxStars = a.getInt(attr, 5);
else if (attr == R.styleable.CustomRatingBar_stars)
mCurrentScore = a.getFloat(attr, 2.5f);
else if (attr == R.styleable.CustomRatingBar_starHalf)
mStarHalfResource = a.getResourceId(attr, android.R.drawable.star_on);
else if (attr == R.styleable.CustomRatingBar_starOn)
mStarOnResource = a.getResourceId(attr, android.R.drawable.star_on);
else if (attr == R.styleable.CustomRatingBar_starOff)
mStarOffResource = a.getResourceId(attr, android.R.drawable.star_off);
else if (attr == R.styleable.CustomRatingBar_starPadding)
mStarPadding = a.getDimension(attr, 0);
else if (attr == R.styleable.CustomRatingBar_onlyForDisplay)
mOnlyForDisplay = a.getBoolean(attr, false);
else if (attr == R.styleable.CustomRatingBar_halfStars)
mHalfStars = a.getBoolean(attr, true);
}
a.recycle();
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public customratingbar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initializeAttributes(attrs, context);
init();
}
void init() {
mStarsViews = new ImageView[mMaxStars];
for (int i = 0; i < mMaxStars; i++) {
ImageView v = createStar();
addView(v);
mStarsViews[i] = v;
}
refreshStars();
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
/**
* hardcore math over here
*
* #param x
* #return
*/
private float getScoreForPosition(float x) {
if (mHalfStars)
return (float) Math.round(((x / ((float) getWidth() / (mMaxStars * 3f))) / 3f) * 2f) / 2;
float value = (float) Math.round((x / ((float) getWidth() / (mMaxStars))));
return value < 0 ? 1 : value;
}
private int getImageForScore(float score) {
if (score > 0)
return Math.round(score) - 1;
else return -1;
}
private void refreshStars() {
boolean flagHalf = (mCurrentScore != 0 && (mCurrentScore % 0.5 == 0)) && mHalfStars;
for (int i = 1; i <= mMaxStars; i++) {
if (i <= mCurrentScore)
mStarsViews[i - 1].setImageResource(mStarOnResource);
else {
if (flagHalf && i - 0.5 <= mCurrentScore)
mStarsViews[i - 1].setImageResource(mStarHalfResource);
else
mStarsViews[i - 1].setImageResource(mStarOffResource);
}
}
}
private ImageView createStar() {
ImageView v = new ImageView(getContext());
LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
params.weight = 1;
v.setPadding((int) mStarPadding, 0, (int) mStarPadding, 0);
v.setAdjustViewBounds(true);
v.setScaleType(ImageView.ScaleType.FIT_CENTER);
v.setLayoutParams(params);
v.setImageResource(mStarOffResource);
return v;
}
private ImageView getImageView(int position) {
try {
return mStarsViews[position];
} catch (Exception e) {
return null;
}
}
#Override
public boolean onTouchEvent(#NonNull MotionEvent event) {
if (mOnlyForDisplay)
return true;
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
animateStarRelease(getImageView(mLastStarId));
mLastStarId = -1;
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(event.getX() - mLastX) > 50)
requestDisallowInterceptTouchEvent(true);
float lastscore = mCurrentScore;
mCurrentScore = getScoreForPosition(event.getX());
if (lastscore != mCurrentScore) {
animateStarRelease(getImageView(mLastStarId));
animateStarPressed(getImageView(getImageForScore(mCurrentScore)));
mLastStarId = getImageForScore(mCurrentScore);
refreshStars();
if (onScoreChanged != null)
onScoreChanged.scoreChanged(mCurrentScore);
}
break;
case MotionEvent.ACTION_DOWN:
mLastX = event.getX();
lastscore = mCurrentScore;
mCurrentScore = getScoreForPosition(event.getX());
animateStarPressed(getImageView(getImageForScore(mCurrentScore)));
mLastStarId = getImageForScore(mCurrentScore);
if (lastscore != mCurrentScore) {
refreshStars();
if (onScoreChanged != null)
onScoreChanged.scoreChanged(mCurrentScore);
}
}
return true;
}
private void animateStarPressed(ImageView star) {
if (star != null)
ViewCompat.animate(star).scaleX(1.2f).scaleY(1.2f).setDuration(100).start();
}
private void animateStarRelease(ImageView star) {
if (star != null)
ViewCompat.animate(star).scaleX(1f).scaleY(1f).setDuration(100).start();
}
public boolean isHalfStars() {
return mHalfStars;
}
public void setHalfStars(boolean halfStars) {
mHalfStars = halfStars;
}
}
and put it inside mainactivity.java
package com.example.ashis.myapplication;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity
{
customratingbar customratingbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
customratingbar= (com.example.ashis.myapplication.customratingbar) findViewById(R.id.rating);
customratingbar.setOnScoreChanged(new customratingbar.IRatingBarCallbacks() {
#Override
public void scoreChanged(float score) {
customratingbar.setScore(score);
}
});
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
and put it in res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomRatingBar">
<attr name="maxStars" format="integer"/>
<attr name="stars" format="float"/>
<attr name="starOff" format="reference|integer"/>
<attr name="starOn" format="reference|integer"/>
<attr name="starHalf" format="reference|integer"/>
<attr name="starPadding" format="dimension"/>
<attr name="onlyForDisplay" format="boolean"/>
<attr name="halfStars" format="boolean"/>
</declare-styleable>
</resources>
and inside res/layout/content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/activity_main"
tools:context="com.example.ashis.myapplication.MainActivity">
<com.example.ashis.myapplication.customratingbar
android:layout_width="300dp"
android:id="#+id/rating"
android:layout_height="20dp"
>
</com.example.ashis.myapplication.customratingbar>
<TextView
android:text="Hello World!"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>

How to use TextViewEx, (Textjustify) clases in android

I am trying to use TextViewEx, (Textjustify) from here
[link] (https://github.com/bluejamesbond/TextJustify-Android )
to get text justification effect in my project but if I copy and paste the files directly to my project then the files are giving error like some thing (other files) are missing. Also I have searched for how to use TextViewEx but I got is this result below
[link] (TextViewEx, (Textjustify))
In this some one told to import the files to the root folder. What does it mean (the root folder). Also if any one has sample code that uses TextViewEx or any other easy way to justify text in Android or sample code that shows justification of text then plz help me Thanks.
Well I have struggled a lot but could not found any help to solve this problem but I have found another alternative to justify text. Use this class if one having problem with justification of text.
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
public class JustifiedTextView extends WebView {
private String core = "<html><body style='text-align:justify;color:rgba(%s);font-size:%dpx;margin: 0px 0px 0px 0px;'>%s</body></html>";
private String text;
private int textColor;
private int backgroundColor;
private int textSize;
public JustifiedTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public JustifiedTextView(Context context, AttributeSet attrs, int i) {
super(context, attrs, i);
init(attrs);
}
#SuppressWarnings("deprecation")
#SuppressLint("NewApi")
public JustifiedTextView(Context context, AttributeSet attrs, int i,
boolean b) {
super(context, attrs, i, b);
init(attrs);
}
private void init(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.JustifiedTextView);
text = a.getString(R.styleable.JustifiedTextView_text);
if (text == null)
text = "";
textColor = a.getColor(R.styleable.JustifiedTextView_textColor,
Color.BLACK);
backgroundColor = a.getColor(
R.styleable.JustifiedTextView_backgroundColor,
Color.TRANSPARENT);
textSize = a.getInt(R.styleable.JustifiedTextView_textSize, 12);
a.recycle();
this.setWebChromeClient(new WebChromeClient() {
});
reloadData();
}
public void setText(String s) {
if (s == null)
this.text = "";
else
this.text = s;
reloadData();
}
#SuppressLint("NewApi")
private void reloadData() {
if (text != null) {
String data = String
.format(core, toRgba(textColor), textSize, text);
Log.d("test", data);
this.loadDataWithBaseURL(null, data, "text/html", "utf-8", null);
}
// set WebView's background color *after* data was loaded.
super.setBackgroundColor(backgroundColor);
// Hardware rendering breaks background color to work as expected.
// Need to use software renderer in that case.
if (android.os.Build.VERSION.SDK_INT >= 11)
this.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null);
}
public void setTextColor(int hex) {
textColor = hex;
reloadData();
}
public void setBackgroundColor(int hex) {
backgroundColor = hex;
reloadData();
}
public void setTextSize(int textSize) {
this.textSize = textSize;
reloadData();
}
#SuppressLint("DefaultLocale")
private String toRgba(int hex) {
String h = Integer.toHexString(hex);
int a = Integer.parseInt(h.substring(0, 2), 16);
int r = Integer.parseInt(h.substring(2, 4), 16);
int g = Integer.parseInt(h.substring(4, 6), 16);
int b = Integer.parseInt(h.substring(6, 8), 16);
return String.format("%d,%d,%d,%d", r, g, b, a);
}
}
this is the attrib.xml class
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="JustifiedTextView">
<attr name="text" format="string" localization="suggested" />
<attr name="textColor" format="color|reference" />
<attr name="backgroundColor" format="color|reference" />
<attr name="textSize" format="integer" min="1" />
</declare-styleable>
</resources>
In the layout class use this as
<com.example.animationtest.JustifiedTextView
android:id="#+id/tjTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
app:text="Your Text Here" >
</com.example.animationtest.JustifiedTextView>
com.example.animationtest is the package name in your project where you put the file JustifiedTextView.class
In the code behind class access to the control as
JustifiedTextView tjTextView;
tvTextView2.setTextSize(convertToDp(24));
tjTextView.setTextColor(Color.RED);
tjTextView.setTextSize((int) convertFromDp(18));
where convertFromDp is used to get text size according to screen.
public float convertFromDp(int input) {
final float scale = getResources().getDisplayMetrics().density;
return ((input - 0.5f) / scale);
}

Android + Swap custom fonts via styles

I have two styles, each declaring a custom font (Normal and Bold).
<style name="label" parent="#android:style/Widget.TextView">
<item name="typeface">#string/custom_font_regular</item>
</style>
<style name="label.bold">
<item name="typeface">#string/custom_font_semibold</item>
</style>
In my xml, I set the custom TextView to use the "label" style, styling the font to normal by default. However, after a user action, I want to swap the normal font for the boldversion via the style label.bold. Is this possible? Keep in mind, I'm trying to avoid calling setTypeface(), which does not take a style as an argument but a pointer to the bold tff which seems wasteful.
Solved. Take a look at my custom textview as an example:
package com.example.ui.components;
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
import com.example.core.ui.R;
public class StandardTextView extends TextView {
public StandardTextView(Context context) {
this(context, null);
}
public StandardTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public StandardTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setTypeFaceFromAttributes(attrs.getStyleAttribute());
}
#Override
public void setTextAppearance(Context context, int resid) {
super.setTextAppearance(context, resid);
setTypeFaceFromAttributes(resid);
}
private void setTypeFaceFromAttributes(int attributeSet) {
if (attributeSet == -1) {
return;
}
TypedArray a = null;
try {
a = getContext().obtainStyledAttributes(attributeSet, R.styleable.StandardTextView);
if (a.getString(R.styleable.StandardTextView_typeface) == null) {
return;
}
String typeFaceString = a.getString(R.styleable.StandardTextView_typeface);
setupTypeface(typeFaceString);
} finally {
if (a != null) {
a.recycle();
}
}
}
private void setupTypeface(String typeFace) {
if (typeFace == null || "".equals(typeFace)) {
return;
}
Resources resources = getResources();
if (resources == null) {
return;
}
AssetManager assetManager = resources.getAssets();
if (assetManager == null) {
return;
}
Typeface tf = Typeface.createFromAsset(assetManager, typeFace);
setTypeface(tf);
}
}
This is how you might use it:
standardTextView.setTextAppearance(ExampleFragment.this.getActivity(), R.style.label_bold);
Attrs:
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<declare-styleable name="StandardTextView">
<attr name="typeface" format="string" />
</declare-styleable>
</resources>
Layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/default_background"
android:orientation="vertical" >
<com.example.ui.components.StandardTextView
android:id="#+id/sure_swipe_create_text"
style="#style/label"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center|top"
android:paddingTop="20dp"
android:text="#string/example" />
</RelativeLayout>

Custom View not responding to touches

I've created a custom view which should change it's background image when pressed, highlighted or disabled. The app runs but the button doesn't change it's background.
here's my code:
public class CustomImageButton extends View {
public CustomImageButton(Context context) {
super(context);
setFocusable(true);
setClickable(true);
}
public CustomImageButton(Context context, AttributeSet attrs) {
super(context, attrs);
setFocusable(true);
setClickable(true);
}
public CustomImageButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setFocusable(true);
setClickable(true);
}
protected Drawable background = super.getBackground();
#Override
public void setBackgroundDrawable(Drawable d) {
// Replace the original background drawable (e.g. image) with a LayerDrawable that
// contains the original drawable slightly edited.
CustomImageButtonBackgroundDrawable layer = new CustomImageButtonBackgroundDrawable(d);
super.setBackgroundDrawable(layer);
}
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int drawableWidth = super.getBackground().getMinimumWidth();
int drawableHeight = super.getBackground().getMinimumHeight();
setMeasuredDimension(drawableWidth, drawableHeight);
}
protected class CustomImageButtonBackgroundDrawable extends LayerDrawable {
protected Drawable lowerlayer;
protected Drawable _highlightedDrawable;
protected int _disabledAlpha = 100;
protected Drawable _pressedDrawable;
public CustomImageButtonBackgroundDrawable(Drawable d) {
super(new Drawable[] { d });
}
#Override
protected boolean onStateChange(int[] states) {
boolean enabled = false;
boolean highlighted = false;
boolean pressed = false;
for (int state : states) {
if (state == android.R.attr.state_enabled)
enabled = true;
else if (state == android.R.attr.state_selected)
highlighted = true;
else if (state == android.R.attr.state_pressed)
pressed = true;
}
mutate();
if (enabled && highlighted) {
ColorFilter colourFilter = new LightingColorFilter(Color.YELLOW, 1);
ScaleDrawable resizedImage = new ScaleDrawable(background, 0, 1.25f, 1.25f);
lowerlayer = resizedImage.getDrawable();
lowerlayer.setColorFilter(colourFilter);
Drawable[] aD = new Drawable[2];
aD[0] = lowerlayer;
aD[1] = background;
LayerDrawable _highlightedDrawable = new LayerDrawable(aD);
setBackgroundDrawable(_highlightedDrawable); // buttons need transparent backgrounds
} else if (!enabled) {
setColorFilter(null);
setAlpha(_disabledAlpha);
} else if (enabled && pressed){
ScaleDrawable smaller = new ScaleDrawable(background, 0, 0.75f, 0.75f);
setBackgroundDrawable(smaller.getDrawable());
} else if(enabled){
setBackgroundDrawable(background);
setColorFilter(null);
}
invalidateSelf();
return super.onStateChange(states);
}
}
}
Here's my xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffff">
<ImageButton
android:id="#+id/title"
android:layout_width="250dp"
android:layout_height="58dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_margin ="25dp"
android:background="#drawable/skintonetitle" />
<custombuttons.CustomImageButton
android:id="#+id/skina1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/title"
android:layout_below="#+id/title"
android:layout_marginTop="35dp"
android:background="#drawable/test_circle"
android:clickable="true"
android:focusable="true" />
</RelativeLayout>
Something I've missed?
It extends from View, not button, so it's not clickable or focusable by default. Adjust with
android:clickable="true"
android:focusable="true"
in your XML.
You can also set these in the constructor of your View class if you want to do it in java:
setFocusable(true);
setClickable(true);
in my case I was using a custom view with a constraint layout as the root .and I was not getting click events on setOnClickListener of my custom view,it turns out that I needed to set android:clickable="false" in the root of my xml for the custom view.apparently , the click event is dispatched to the root of my custom view xml rather than to the custom view it self (i.e setOnClickListener of the custom view )

Categories

Resources