Strings with HTML font styles from external DB - android

Hi, guys! I'm working on app which uses a external sqlite database . I'm using a sample source code and I would like to some excerpts from the entries present bold or italic style or a different color.
For example, if I have an entry like this: Black is my favorite color. I would like my string recognize the HTML tags. The word "black" in my example should be in bold.
I'm a newbie and I need a help in details. This is my code:
WordView.java
public class WordView extends TextView implements OnTouchListener {
private PopupView popup;
private String infoWord;
private ScrollView parent;
private boolean mClickEnabled;
private Typeface transTypeFace, transTypeFaceBold;
private static final Map<String, String[]> FONTS = new HashMap<String, String[]>();
static {
FONTS.put("sans", new String[] { "DejaVuSansCondensed.ttf", "DejaVuSansCondensed-Bold.ttf"});
FONTS.put("serif", new String[] { "DejaVuSerifCondensed.ttf", "DejaVuSerifCondensed-Bold.ttf"});
}
private class Type1Span extends ClickableSpan {
String word;
public Type1Span(String word) {
this.word = word;
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(touchedInstance == this);
ds.setTypeface(transTypeFace);
}
#Override
public void onClick(View widget) {
if (mClickEnabled) {
Uri uri = Uri.parse("ecidiomas://" + word);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.addCategory(Intent.CATEGORY_DEFAULT);
widget.getContext().startActivity(intent);
}
}
};
private class Type2Span extends Type1Span {
public Type2Span(String word) {
super(word);
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setTypeface(transTypeFaceBold);
}
}
private class TranscriptionTypeSpan extends ForegroundColorSpan {
public TranscriptionTypeSpan(int color) {
super(color);
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setTypeface(transTypeFaceBold);
//ds.setTypeface(Typeface.DEFAULT_BOLD);
}
}
private Type1Span touchedInstance;
public WordView(Context context) {
super(context);
init();
}
public WordView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public WordView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
Context ctx = getContext();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(ctx);
String defaultType = "sans";
String fontType = sp.getString(App.PreferenceKeys.preference_font_idx, defaultType);
if (!FONTS.containsKey(fontType)) fontType = defaultType;
transTypeFace = Typeface.createFromAsset(ctx.getAssets(), FONTS.get(fontType)[0]);
transTypeFaceBold = Typeface.createFromAsset(ctx.getAssets(), FONTS.get(fontType)[1]);
setTypeface(transTypeFaceBold);
setMovementMethod(LinkMovementMethod.getInstance());
setOnTouchListener(this);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
ViewParent p = getParent();
if (p instanceof ScrollView)
parent = (ScrollView) p;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return event.getAction() == MotionEvent.ACTION_DOWN ?
true : super.onTouchEvent(event);
}
public void setWordInfo(String word, String translation, String text) {
infoWord = word;
translation = translation.trim();
translation = TextUtils.isEmpty(translation) ? "" : (translation + '\n');
setText(infoWord.trim().toUpperCase() + "\n" + translation + "\n"+ text);
}
#Override
public void setText(CharSequence text, BufferType type) {
Integer currentType = LinksFinder.getType(infoWord != null ? infoWord : ""); //XXX
ArrayList<LinksFinder.LinkSpec> links = LinksFinder.getLinks(text.toString());
if (links == null) {
super.setText(text, type);
return;
}
SpannableString ss = new SpannableString(text);
int links_length = links.size();
for (int i = 0; i < links_length; ++i) {
LinksFinder.LinkSpec l = links.get(i);
CharacterStyle span;
if (LinksFinder.TRANSCRIPTION == l.type) {
span = new TranscriptionTypeSpan(0xffc91111);
} else if (currentType == l.type) {
span = new Type2Span(l.url);
} else {
span = new Type1Span(l.url);
}
ss.setSpan(span, l.start, l.end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
super.setText(ss, type);
}
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN
|| event.getAction() == MotionEvent.ACTION_MOVE) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= getTotalPaddingLeft();
y -= getTotalPaddingTop();
int xx = getRealPosX(x);
int yy = getRealPosY(y);
x += getScrollX();
y += getScrollY();
Layout layout = getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
Type1Span[] candidates = ((Spannable) getText()).getSpans(off, off, Type1Span.class);
if (candidates.length > 0) {
touchedInstance = candidates[0];
} else {
touchedInstance = null;
}
if (mClickEnabled && popup != null && touchedInstance != null)
popup.setPopupText(xx, yy, touchedInstance.word);
} else {
if (popup != null)
popup.clear();
if (touchedInstance != null) {
touchedInstance = null;
}
}
return false;
}
public void setPopup(PopupView popup) {
this.popup = popup;
this.popup.setTypeFace(transTypeFaceBold);
}
private int getRealPosX(int val) {
return parent == null ? val : val - parent.getScrollX();
}
private int getRealPosY(int val) {
return parent == null ? val : val - parent.getScrollY();
}
public void setClickEnabled(boolean enabled) {
mClickEnabled = enabled;
}
}
WordAdapter.java
class WordAdapter extends CursorAdapter implements Filterable, DB {
private String[] QUERY_PROJECTION = new String[] { COLUMN_ID, COLUMN_WORD };
private final int WORD_COLUMN_INDEX;
private SQLiteDatabase db;
public WordAdapter(Context context, Cursor c, SQLiteDatabase db) {
super(context, c);
WORD_COLUMN_INDEX = c.getColumnIndexOrThrow(COLUMN_WORD);
this.db = db;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final LayoutInflater inflater = LayoutInflater.from(context);
final TextView view = (TextView) inflater.inflate(
R.layout.simple_dropdown_item_1line, parent, false);
view.setText(cursor.getString(WORD_COLUMN_INDEX));
return view;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
((TextView) view).setText(cursor.getString(WORD_COLUMN_INDEX));
}
#Override
public String convertToString(Cursor cursor) {
return cursor.getString(WORD_COLUMN_INDEX);
}
#Override
public Cursor runQueryOnBackgroundThread(CharSequence s) {
Cursor c = null;
if (s != null)
c = db.query(DB.TABLE_WORDS, QUERY_PROJECTION, getLike(s.toString().toLowerCase()), null, null, null, null);
return c;
}
private String getLike(String s) {
return DB.COLUMN_WORD + ">= '" + s + "' AND " + DB.COLUMN_WORD + "< '" + s + '\u044F' +"'";
}
}

Related

Android LuckyWheel Library add onClick method on Canvas item

I am using this library to draw a circle with eight equal triangular parts and rotate them. Now I want to add an OnClick feature, so when user clicks on one of the triangles it will rotate to the selected position. This library already has code for rotating an item by it's index, but I cannot figure out how to find the index of the triangle which has been clicked. Has anyone worked with this before? Any help is appreciated.
Code:
LuckyWheelView.java
public class LuckyWheelView extends RelativeLayout implements PielView.PieRotateListener {
private int mBackgroundColor;
private int mTextColor;
private int mTopTextSize;
private int mSecondaryTextSize;
private int mBorderColor;
private int mTopTextPadding;
private int mEdgeWidth;
private Drawable mCenterImage;
private Drawable mCursorImage;
private PielView pielView;
private ImageView ivCursorView;
private LuckyRoundItemSelectedListener mLuckyRoundItemSelectedListener;
#Override
public void rotateDone(int index) {
if (mLuckyRoundItemSelectedListener != null) {
mLuckyRoundItemSelectedListener.LuckyRoundItemSelected(index);
}
}
public interface LuckyRoundItemSelectedListener {
void LuckyRoundItemSelected(int index);
}
public void setLuckyRoundItemSelectedListener(LuckyRoundItemSelectedListener listener) {
this.mLuckyRoundItemSelectedListener = listener;
}
public LuckyWheelView(Context context) {
super(context);
init(context, null);
}
public LuckyWheelView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
/**
* #param ctx
* #param attrs
*/
private void init(Context ctx, AttributeSet attrs) {
if (attrs != null) {
TypedArray typedArray = ctx.obtainStyledAttributes(attrs, R.styleable.LuckyWheelView);
mBackgroundColor = typedArray.getColor(R.styleable.LuckyWheelView_lkwBackgroundColor, 0xffcc0000);
mTopTextSize = typedArray.getDimensionPixelSize(R.styleable.LuckyWheelView_lkwTopTextSize, (int) LuckyWheelUtils.convertDpToPixel(10f, getContext()));
mSecondaryTextSize = typedArray.getDimensionPixelSize(R.styleable.LuckyWheelView_lkwSecondaryTextSize, (int) LuckyWheelUtils.convertDpToPixel(20f, getContext()));
mTextColor = typedArray.getColor(R.styleable.LuckyWheelView_lkwTopTextColor, 0);
mTopTextPadding = typedArray.getDimensionPixelSize(R.styleable.LuckyWheelView_lkwTopTextPadding, (int) LuckyWheelUtils.convertDpToPixel(10f, getContext())) + (int) LuckyWheelUtils.convertDpToPixel(10f, getContext());
mCursorImage = typedArray.getDrawable(R.styleable.LuckyWheelView_lkwCursor);
mCenterImage = typedArray.getDrawable(R.styleable.LuckyWheelView_lkwCenterImage);
mEdgeWidth = typedArray.getInt(R.styleable.LuckyWheelView_lkwEdgeWidth, 10);
mBorderColor = typedArray.getColor(R.styleable.LuckyWheelView_lkwEdgeColor, 0);
typedArray.recycle();
}
LayoutInflater inflater = LayoutInflater.from(getContext());
FrameLayout frameLayout = (FrameLayout) inflater.inflate(R.layout.lucky_wheel_layout, this, false);
pielView = frameLayout.findViewById(R.id.pieView);
ivCursorView = frameLayout.findViewById(R.id.cursorView);
pielView.setPieRotateListener(this);
pielView.setPieBackgroundColor(mBackgroundColor);
pielView.setTopTextPadding(mTopTextPadding);
pielView.setTopTextSize(mTopTextSize);
pielView.setSecondaryTextSizeSize(mSecondaryTextSize);
pielView.setPieCenterImage(mCenterImage);
pielView.setBorderColor(mBorderColor);
pielView.setBorderWidth(mEdgeWidth);
if (mTextColor != 0)
pielView.setPieTextColor(mTextColor);
ivCursorView.setImageDrawable(mCursorImage);
addView(frameLayout);
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//This is to control that the touch events triggered are only going to the PieView
for (int i = 0; i < getChildCount(); i++) {
if (isPielView(getChildAt(i))) {
return super.dispatchTouchEvent(ev);
}
}
return false;
}
private boolean isPielView(View view) {
if (view instanceof ViewGroup) {
for (int i = 0; i < getChildCount(); i++) {
if (isPielView(((ViewGroup) view).getChildAt(i))) {
return true;
}
}
}
return view instanceof PielView;
}
public void setLuckyWheelBackgrouldColor(int color) {
pielView.setPieBackgroundColor(color);
}
public void setLuckyWheelCursorImage(int drawable) {
ivCursorView.setBackgroundResource(drawable);
}
public void setLuckyWheelCenterImage(Drawable drawable) {
pielView.setPieCenterImage(drawable);
}
public void setBorderColor(int color) {
pielView.setBorderColor(color);
}
public void setLuckyWheelTextColor(int color) {
pielView.setPieTextColor(color);
}
/**
* #param data
*/
public void setData(List<LuckyItem> data) {
pielView.setData(data);
}
/**
* #param numberOfRound
*/
public void setRound(int numberOfRound) {
pielView.setRound(numberOfRound);
}
/**
* #param fixedNumber
*/
public void setPredeterminedNumber(int fixedNumber) {
pielView.setPredeterminedNumber(fixedNumber);
}
public void startLuckyWheelWithTargetIndex(int index) {
pielView.rotateTo(index);
}
}
MainActivity.java
public class MainActivity extends Activity {
List<LuckyItem> data = new ArrayList<>();
LuckyWheelView luckyWheelView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
luckyWheelView = (LuckyWheelView) findViewById(R.id.luckyWheel);
LuckyItem luckyItem1 = new LuckyItem();
/*luckyItem1.topText = "100";
luckyItem1.icon = R.drawable.test1;*/
luckyItem1.color = 0xffFFF3E0;
data.add(luckyItem1);
LuckyItem luckyItem2 = new LuckyItem();
/*luckyItem2.topText = "200";
luckyItem2.icon = R.drawable.test2;*/
luckyItem2.color = 0xffFFE0B2;
data.add(luckyItem2);
LuckyItem luckyItem3 = new LuckyItem();
/*uckyItem3.topText = "300";
luckyItem3.icon = R.drawable.test3;*/
luckyItem3.color = 0xffFFCC80;
data.add(luckyItem3);
//////////////////
final LuckyItem luckyItem4 = new LuckyItem();
/*luckyItem4.topText = "400";
luckyItem4.icon = R.drawable.test4;*/
luckyItem4.color = 0xffFFF3E0;
data.add(luckyItem4);
LuckyItem luckyItem5 = new LuckyItem();
/*luckyItem5.topText = "500";
luckyItem5.icon = R.drawable.test5;*/
luckyItem5.color = 0xffFFE0B2;
data.add(luckyItem5);
LuckyItem luckyItem6 = new LuckyItem();
/*luckyItem6.topText = "600";
luckyItem6.icon = R.drawable.test6;*/
luckyItem6.color = 0xffFFCC80;
data.add(luckyItem6);
//////////////////
//////////////////////
LuckyItem luckyItem7 = new LuckyItem();
/*luckyItem7.topText = "700";
luckyItem7.icon = R.drawable.test7;*/
luckyItem7.color = 0xffFFF3E0;
data.add(luckyItem7);
LuckyItem luckyItem8 = new LuckyItem();
/*luckyItem8.topText = "800";
luckyItem8.icon = R.drawable.test8;*/
luckyItem8.color = 0xffFFE0B2;
data.add(luckyItem8);
/////////////////////
luckyWheelView.setData(data);
luckyWheelView.setRound(0);
luckyWheelView.setLuckyRoundItemSelectedListener(new LuckyWheelView.LuckyRoundItemSelectedListener() {
#Override
public void LuckyRoundItemSelected(int index) {
// Toast.makeText(getApplicationContext(), data.get(index).topText, Toast.LENGTH_SHORT).show();
}
});
}
}

how to get expandable textview width to set its trim length to 1 line

i'm using expandable textview to display some part of the text and when user clicks on this textview then user can see whole String of that text for that i'm using this example but the problem is the trim length of the expandable textview its set to fixed, but i want to set the trim length dynamic based on screen size with only one line, when i use trim_length = 200 the text displayed is of 3 lines, here is my code...
ExpandableTextView.java
public class ExpandableTextView extends TextView {
private static final int DEFAULT_TRIM_LENGTH = 200;
private static final String ELLIPSIS = ".....";
private CharSequence originalText;
private CharSequence trimmedText;
private BufferType bufferType;
private boolean trim = true;
private int trimLength;
public ExpandableTextView(Context context) {
this(context, null);
}
public ExpandableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ExpandableTextView);
this.trimLength = typedArray.getInt(R.styleable.ExpandableTextView_trimLength, DEFAULT_TRIM_LENGTH);
typedArray.recycle();
setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
trim = !trim;
setText();
requestFocusFromTouch();
}
});
}
private void setText() {
super.setText(getDisplayableText(), bufferType);
}
private CharSequence getDisplayableText() {
return trim ? trimmedText : originalText;
}
#Override
public void setText(CharSequence text, BufferType type) {
originalText = text;
trimmedText = getTrimmedText(text);
bufferType = type;
setText();
}
private CharSequence getTrimmedText(CharSequence text) {
if (originalText != null && originalText.length() > trimLength) {
return new SpannableStringBuilder(originalText, 0, trimLength + 1).append(ELLIPSIS);
} else {
return originalText;
}
}
public CharSequence getOriginalText() {
return originalText;
}
public void setTrimLength(int trimLength) {
this.trimLength = trimLength;
trimmedText = getTrimmedText(originalText);
setText();
}
public int getTrimLength() {
return trimLength;
}
}
ExpandableTextView expandableTextView = (ExpandableTextView) findViewById(R.id.lorem_ipsum);
expandableTextView.setText(yourText);
you can do it like this
public class ExpandableTextView extends TextView
{
// copy off TextView.LINES
private static final int MAXMODE_LINES = 1;
// private OnExpandListener onExpandListener;
private final int maxLines;
private boolean expanded;
public ExpandableTextView(final Context context)
{
this(context, null);
}
public ExpandableTextView(final Context context, final AttributeSet attrs)
{
this(context, attrs, 0);
}
public ExpandableTextView(final Context context, final AttributeSet attrs, final int defStyle)
{
super(context, attrs, defStyle);
// read attributes
final TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.ExpandableTextView, defStyle, 0);
// this.animationDuration = attributes.getInt(R.styleable.ExpandableTextView_trimLength, 200);
attributes.recycle();
// keep the original value of maxLines
this.maxLines = this.getMaxLines();
}
#Override
public int getMaxLines()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
{
return super.getMaxLines();
}
try
{
final Field mMaxMode = TextView.class.getField("mMaxMode");
mMaxMode.setAccessible(true);
final Field mMaximum = TextView.class.getField("mMaximum");
mMaximum.setAccessible(true);
final int mMaxModeValue = (int) mMaxMode.get(this);
final int mMaximumValue = (int) mMaximum.get(this);
return mMaxModeValue == MAXMODE_LINES ? mMaximumValue : -1;
}
catch (final Exception e)
{
return -1;
}
}
public boolean toggle()
{
return this.expanded
? this.collapse()
: this.expand();
}
public boolean expand()
{
if (!this.expanded && this.maxLines >= 0)
{
// set maxLines to MAX Integer, so we can calculate the expanded height
this.setMaxLines(Integer.MAX_VALUE);
// keep track of current status
ExpandableTextView.this.expanded = true;
return true;
}
return false;
}
public boolean collapse()
{
if (this.expanded && this.maxLines >= 0)
{
ExpandableTextView.this.setMaxLines(ExpandableTextView.this.maxLines);
// keep track of current status
ExpandableTextView.this.expanded = false;
return true;
}
return false;
}
}
activity.xml
<com.yourpackagename.ExpandableTextView
android:id="#+id/expandableTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
/>
activity.java
ExpandableTextView expandableTextView = (ExpandableTextView) this.findViewById(R.id.expandableTextView);
expandableTextView.setOnClickListener(new View.OnClickListener()
{
#SuppressWarnings("ConstantConditions")
#Override
public void onClick(final View v)
{
expandableTextView.toggle();
}
});

Change number of columns in gridview with animation ( item to item )

I want to create a animation in android with Gridview. The animation will be when I will change the number of columns from 2 to 4.
I used the following line to change the number of columns:
If (true)
gridView.setNumColumns(2);
Else
gridView.setNumColumns(4);
I want to achieve animation like this:
https://www.youtube.com/watch?v=1NkuChdWA_I
I need it too and then i created the following class:
/**
* Created by Butzke on 19/05/2017.
*/
public class GridViewAnimated extends GridView {
private int animationDuration = 300, nextColumns;
private boolean animating = false, waitingScroll, shouldWait = true;
private GridViewAnimationListener animationListener;
public GridViewAnimated(Context context) {
super(context);
init();
}
public GridViewAnimated(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public GridViewAnimated(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
#TargetApi(21)
public GridViewAnimated(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
#Override
public int computeVerticalScrollOffset() {
return super.computeVerticalScrollOffset();
}
private void init() {
this.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
}
public void setAnimating(boolean animating) {
this.animating = animating;
}
#Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
if (waitingScroll) {
super.onScrollChanged(l, t, oldl, oldt);
if (computeVerticalScrollOffset() == 0) {
setEnabled(true);
waitingScroll = false;
setAnimating(false);
setNumColumns(nextColumns);
}
} else if (!animating) {
super.onScrollChanged(l, t, oldl, oldt);
}
}
public int getAnimationDuration() {
return animationDuration;
}
public void setAnimationDuration(int animationDuration) {
this.animationDuration = animationDuration;
}
public interface GridViewAnimationListener {
void onAnimationStart(Animator animator);
void onAnimationEnd(Animator animator);
void onAnimationCancel(Animator animator);
void onAnimationRepeat(Animator animator);
}
public GridViewAnimationListener getAnimationListener() {
return animationListener;
}
public void setAnimationListener(GridViewAnimationListener animationListener) {this.animationListener = animationListener;}
public void removeAt(int... positions) {
ArrayList<MyInteger> ints = new ArrayList<>();
for (Integer pos : positions) {
ints.add(new MyInteger(pos));
}
Collections.sort(ints);
int lowest = 99999, highest = 0;
for (MyInteger pos : ints) {
lowest = lowest < pos.getValue() ? lowest : pos.getValue();
highest = highest > pos.getValue() ? highest : pos.getValue();
}
if (lowest >= 0 && highest <= getChildCount()) {
ViewsVO originalViews = getOriginalViews();
for (MyInteger pos : ints) {
getAdapter().removeAt(pos.getValue());
}
getAdapter().notifyDataSetChanged();
animateChildViews(originalViews);
}
}
#Override
public void setAdapter(ListAdapter adapter) {
if (adapter instanceof GridViewAnimatedAdapter) {
super.setAdapter(adapter);
} else {
Log.e("GridViewAnimated", "Adapter needs to be instance of GridViewAnimatedAdapter");
Toast.makeText(getContext(), "Adapter needs to be instance of GridViewAnimatedAdapter", Toast.LENGTH_SHORT).show();
}
}
#Override
public GridViewAnimatedAdapter getAdapter() {
return (GridViewAnimatedAdapter) super.getAdapter();
}
#Override
public void setNumColumns(int numColumns) {
if (getAdapter() == null || !getAdapter().hasStableIds() || getChildCount() == 0) {
super.setNumColumns(numColumns);
setAnimating(false);
return;
} else if (animating) {
return;
}
setAnimating(true);
if (computeVerticalScrollOffset() > 0) {
waitingScroll = true;
setEnabled(false);
smoothScrollToPosition(0);
nextColumns = numColumns;
return;
}
ViewsVO originalViews = getOriginalViews();
super.setNumColumns(numColumns);
getAdapter().notifyDataSetChanged();
animateChildViews(originalViews);
}
private ViewsVO getOriginalViews() {
ViewsVO originalViews = new ViewsVO();
for (int i = 0; i < getChildCount(); i++) {
originalViews.addView(getChildAt(i));
}
return originalViews;
}
private void animateChildViews(final ViewsVO originalViews) {
final GridViewAnimated gridView = this;
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
gridView.getViewTreeObserver().removeOnPreDrawListener(this);
ViewsVO newViews = new ViewsVO();
if (Build.VERSION.SDK_INT >= 21) {
for (int i = 0, z = getChildCount() - 1; z >= 0; z--, i++) {
gridView.getChildAt(z).setTranslationZ(i);
}
}
boolean hasFirst = false;
View firstView = null, lastView = null;
float firstHeight = 0, lastHeight = 0;
ViewsVO newViewsFirstTime = new ViewsVO();
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
ViewVO nView = newViews.addView(view);
ViewVO oView = originalViews.getView(view.getId());
if (oView != null) {
view.setScaleX(getScaleX(oView, nView));
view.setScaleY(getScaleY(oView, nView));
view.setTranslationX(getTranslateX(oView, nView));
view.setTranslationY(getTranslateY(oView, nView));
if (!hasFirst) {
firstView = view;
firstHeight = oView.getHeight();
hasFirst = true;
}
lastView = view;
lastHeight = oView.getHeight();
animateView(view);
} else {
newViewsFirstTime.addView(nView);
}
}
for (int i = 0; i < newViewsFirstTime.size(); i++) {
try {
View view = newViewsFirstTime.getViews().get(i).getView();
view.getId();
view.setScaleX(view.getId() > firstView.getId() ? firstView.getScaleX() : lastView.getScaleX());
view.setScaleY(view.getId() > firstView.getId() ? firstView.getScaleY() : lastView.getScaleX());
view.setTranslationX(view.getId() > firstView.getId() ? firstView.getTranslationX() : lastView.getTranslationX());
view.setTranslationY(view.getId() > firstView.getId() ? 0 - firstHeight : lastView.getTranslationY() + lastHeight);
animateView(view);
} catch (Exception ex) {
ex.printStackTrace();
}
}
return false;
}
});
}
private void animateView(final View view) {
ViewPropertyAnimator animator = view.animate().setDuration(animationDuration).translationX(0).translationY(0).scaleX(1).scaleY(1).setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {animationListener.onAnimationStart(animator);}
#Override
public void onAnimationEnd(Animator animator) {
setAnimating(false);
animationListener.onAnimationEnd(animator);
ViewGroup.LayoutParams params = view.getLayoutParams();
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
params.height = ViewGroup.LayoutParams.MATCH_PARENT;
view.setLayoutParams(params);
}
#Override
public void onAnimationCancel(Animator animator) {animationListener.onAnimationCancel(animator);}
#Override
public void onAnimationRepeat(Animator animator) {animationListener.onAnimationRepeat(animator);}
});
if (Build.VERSION.SDK_INT >= 21) {
animator.translationZ(0);
}
}
private float getTranslateX(ViewVO ov, ViewVO nv) {return ov.getPosX() - nv.getPosX() - ((ov.getWidth() < nv.getWidth() ? nv.getWidth() - ov.getWidth() : ov.getWidth() - nv.getWidth()) * (ov.getWidth() < nv.getWidth() ? 0.5f : -0.5f));}
private float getTranslateY(ViewVO ov, ViewVO nv) {return ov.getPosY() - nv.getPosY() - ((ov.getHeight() < nv.getHeight() ? nv.getHeight() - ov.getHeight() : ov.getHeight() - nv.getHeight()) * (ov.getHeight() < nv.getHeight() ? 0.5f : -0.5f));}
private float getScaleY(ViewVO ov, ViewVO nv) {
return ov.getHeight() / nv.getHeight();
}
private float getScaleX(ViewVO ov, ViewVO nv) {
return ov.getWidth() / nv.getWidth();
}
private class ViewsVO {
private ArrayList<ViewVO> views;
private int size() {
return views.size();
}
private ViewsVO() {
views = new ArrayList<>();
}
private ViewVO addView(View view) {
ViewVO v = new ViewVO(view);
addView(v);
return v;
}
private void addView(ViewVO view) {
views.add(view);
}
private ViewVO getView(long id) {
for (ViewVO view : views) {
if (view.getId() == id) {
return view;
}
}
return null;
}
private ArrayList<ViewVO> getViews() {
return views;
}
}
private class ViewVO {
private View view;
private int id;
private float posY;
private float posX;
private float width;
private float height;
private ViewVO(View view) {
this.view = view;
id = view.getId();
posX = view.getLeft();
posY = view.getTop();
width = view.getWidth();
height = view.getHeight();
}
public int getId() {
return id;
}
public View getView() {
return view;
}
private float getWidth() {
return width;
}
private float getHeight() {
return height;
}
private float getPosY() {
return posY;
}
private float getPosX() {
return posX;
}
}
public static class GridViewAnimatedAdapter extends ArrayAdapter {
private List objects;
public GridViewAnimatedAdapter(Context context, int resource, List objects) {
super(context, resource, objects);
this.objects = objects;
}
public void removeAt(int pos) {objects.remove(pos);}
#Override
public boolean hasStableIds() {
return true;
}
public View dealViewToAnimation(View view) {
ViewGroup.LayoutParams params = view.getLayoutParams();
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
params.height = ViewGroup.LayoutParams.MATCH_PARENT;
view.setLayoutParams(params);
return view;
}
}
private class MyInteger implements Comparable<MyInteger> {
private int value;
public MyInteger(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
#Override
public int compareTo(MyInteger another) {return value > another.getValue() ? -1 : (value == another.getValue() ? 0 : 1);}}
}
And to use it is quite simple,
The adapter of GridView needs to extends GridViewAnimatedAdapter and:
getView(): To set an ID to each view and in the end of the method getView, needs to finish using the method dealViewToAnimation(View view) Ex:
#Override
public View getView(int position, View view, ViewGroup parent) {
...
view.setId(images.getId());
...
return dealViewToAnimation(view);
}
You can also set a listener to animation status:
gridView.setAnimationListener(new GridViewAnimated.GridViewAnimationListener() {
#Override
public void onAnimationStart(Animator animator) {
mListMenu.setVisible(false);
}
#Override
public void onAnimationEnd(Animator animator) {
mListMenu.setVisible(true);
gridView.setAnimating(false);
}
#Override
public void onAnimationCancel(Animator animator) {}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
With this GridView you can animate changes in column number and animate removal of itens...
Animating change of column number:
gridView.setNumColumns(5);
Animating removal of itens:
gridView.removeAt(2, 7, 4);
gridView.removeAt(2);
When more than one, doesn't matter the order, the method will check the order and remove from the highest to lowest, considering that the highest id (that image added to the view) is the first view...
But despite it doesn't have the scale proportion animation like in the GridViewAnimated, it's better with RecyclerView, GridLayoutManager and DefaultItemAnimator, since it changes columns number and doesn't scroll...
GridLayoutmanager gridLayoutManager = new GridLayoutManager(context, 2);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
And then when you need to change the columns:
gridLayoutManager.requestSimpleAnimationsInNextLayout();
gridLayoutManager.setSpanCount(newNumberOfColumns);

android : open keyboard in dialogfragment

I have a custom view PasscodeView in my dialog fragment layout.
PasscodeView.java:
public class PasscodeView extends ViewGroup {
EditText mEditText;
int mDigitCount;
private int mDigitWidth;
private int mDigitRadius;
private int mOuterStrokeWidth;
private int mInnerStrokeWidth;
private int mDigitInnerRadius;
private int mDigitSpacing;
private int mDigitElevation;
private int mControlColor;
private int mHighlightedColor;
private int mInnerColor;
private int mInnerBorderColor;
private OnFocusChangeListener mOnFocusChangeListener;
private PasscodeEntryListener mPasscodeEntryListener;
public PasscodeView(Context context) {
this(context, null);
}
public PasscodeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PasscodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// Get style information
TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.PasscodeView);
mDigitCount = array.getInt(R.styleable.PasscodeView_numDigits, 4);
// Dimensions
DisplayMetrics metrics = getResources().getDisplayMetrics();
mDigitRadius = array.getDimensionPixelSize(R.styleable.PasscodeView_digitRadius,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, metrics));
mOuterStrokeWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, metrics);
mInnerStrokeWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, metrics);
mDigitInnerRadius = mDigitRadius - ((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6, metrics));
mDigitWidth = (mDigitRadius + mOuterStrokeWidth) * 2;
mDigitSpacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, metrics);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mDigitElevation = array.getDimensionPixelSize(R.styleable.PasscodeView_digitElevation, 0);
}
// Get theme to resolve defaults
Resources.Theme theme = getContext().getTheme();
mControlColor = Color.DKGRAY;
// Text colour, default to android:colorControlNormal from theme
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
TypedValue controlColor = new TypedValue();
theme.resolveAttribute(android.R.attr.colorControlNormal, controlColor, true);
mControlColor = controlColor.resourceId > 0 ? getResources().getColor(controlColor.resourceId) :
controlColor.data;
}
mControlColor = array.getColor(R.styleable.PasscodeView_controlColor, mControlColor);
// Accent colour, default to android:colorAccent from theme
mHighlightedColor = Color.LTGRAY;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
TypedValue accentColor = new TypedValue();
theme.resolveAttribute(R.attr.colorControlHighlight, accentColor, true);
mHighlightedColor = accentColor.resourceId > 0 ? getResources().getColor(accentColor.resourceId) :
accentColor.data;
}
mHighlightedColor = array.getColor(R.styleable.PasscodeView_controlColorActivated, mHighlightedColor);
//color for the inner circle
mInnerColor = Color.CYAN;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
TypedValue innerColor = new TypedValue();
theme.resolveAttribute(android.R.attr.colorPrimary, innerColor, true);
mInnerColor = innerColor.resourceId > 0 ? getResources().getColor(innerColor.resourceId) :
innerColor.data;
}
mInnerColor = array.getColor(R.styleable.PasscodeView_digitColorFilled, mInnerColor);
//color for the inner circle border
mInnerBorderColor = Color.GREEN;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
TypedValue innerBorderColor = new TypedValue();
theme.resolveAttribute(android.R.attr.colorPrimaryDark, innerBorderColor, true);
mInnerBorderColor = innerBorderColor.resourceId > 0 ? getResources().getColor(innerBorderColor.resourceId) :
innerBorderColor.data;
}
mInnerBorderColor = array.getColor(R.styleable.PasscodeView_digitColorBorder, mInnerBorderColor);
// Recycle the typed array
array.recycle();
// Add child views
setupViews();
}
#Override
public boolean shouldDelayChildPressedState() {
return false;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Measure children
for (int i = 0; i < getChildCount(); i++) {
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
}
// Calculate the size of the view
int width = (mDigitWidth * mDigitCount) + (mDigitSpacing * (mDigitCount - 1));
setMeasuredDimension(
width + getPaddingLeft() + getPaddingRight() + (mDigitElevation * 2),
mDigitWidth + getPaddingTop() + getPaddingBottom() + (mDigitElevation * 2));
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// Position the child views
for (int i = 0; i < mDigitCount; i++) {
View child = getChildAt(i);
int left = i * mDigitWidth + (i > 0 ? i * mDigitSpacing : 0);
child.layout(
left + getPaddingLeft() + mDigitElevation,
getPaddingTop() + (mDigitElevation / 2),
left + getPaddingLeft() + mDigitElevation + mDigitWidth,
getPaddingTop() + (mDigitElevation / 2) + mDigitWidth);
}
// Add the edit text as a 1px wide view to allow it to focus
getChildAt(mDigitCount).layout(0, 0, 1, getMeasuredHeight());
}
private void setupViews() {
setWillNotDraw(false);
// Add a digit view for each digit
for (int i = 0; i < mDigitCount; i++) {
DigitView digitView = new DigitView(getContext(), i);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
digitView.setElevation(mDigitElevation);
}
addView(digitView);
}
// Add an "invisible" edit text to handle input
mEditText = new EditText(getContext());
mEditText.setBackgroundColor(getResources().getColor(android.R.color.transparent));
mEditText.setTextColor(getResources().getColor(android.R.color.transparent));
mEditText.setCursorVisible(false);
mEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(mDigitCount)});
mEditText.setInputType(InputType.TYPE_CLASS_NUMBER);
mEditText.setKeyListener(DigitsKeyListener.getInstance("1234567890"));
mEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
mEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
// Update the selected state of the views
int length = mEditText.getText().length();
updateChilViewSelectionStates(length, hasFocus);
// Make sure the cursor is at the end
mEditText.setSelection(length);
// Provide focus change events to any listener
if (mOnFocusChangeListener != null) {
mOnFocusChangeListener.onFocusChange(PasscodeView.this, hasFocus);
}
}
});
mEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
int length = s.length();
updateChilViewSelectionStates(length, mEditText.hasFocus());
if (length == mDigitCount && mPasscodeEntryListener != null) {
mPasscodeEntryListener.onPasscodeEntered(s.toString());
}
}
});
addView(mEditText);
invalidate();
}
private void updateChilViewSelectionStates(int length, boolean hasFocus) {
for (int i = 0; i < mDigitCount; i++) {
getChildAt(i).setSelected(hasFocus && i == length);
}
}
/**
* Get the {#link Editable} from the EditText
*
* #return
*/
public Editable getText() {
return mEditText.getText();
}
/**
* Set text to the EditText
*
* #param text
*/
public void setText(CharSequence text) {
if (text.length() > mDigitCount) {
text = text.subSequence(0, mDigitCount);
}
mEditText.setText(text);
invalidateChildViews();
}
/**
* Clear passcode input
*/
public void clearText() {
mEditText.setText("");
invalidateChildViews();
}
private void invalidateChildViews() {
for (int i = 0; i < mDigitCount; i++) {
getChildAt(i).invalidate();
}
}
public void setPasscodeEntryListener(PasscodeEntryListener mPasscodeEntryListener) {
this.mPasscodeEntryListener = mPasscodeEntryListener;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
requestToShowKeyboard();
return true;
}
return super.onTouchEvent(event);
}
/**
* Requests the view to be focused and the keyboard to be popped-up
*/
public void requestToShowKeyboard() {
// Make sure this view is focused
mEditText.requestFocus();
// Show keyboard
InputMethodManager inputMethodManager = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.showSoftInput(mEditText, 0);
}
#Override
public OnFocusChangeListener getOnFocusChangeListener() {
return mOnFocusChangeListener;
}
#Override
public void setOnFocusChangeListener(OnFocusChangeListener l) {
mOnFocusChangeListener = l;
}
#Override
protected Parcelable onSaveInstanceState() {
Parcelable parcelable = super.onSaveInstanceState();
SavedState savedState = new SavedState(parcelable);
savedState.editTextValue = mEditText.getText().toString();
return savedState;
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
SavedState savedState = (SavedState) state;
super.onRestoreInstanceState(savedState.getSuperState());
mEditText.setText(savedState.editTextValue);
mEditText.setSelection(savedState.editTextValue.length());
}
/**
* Listener that gets notified when the complete passcode has been entered
*/
public interface PasscodeEntryListener {
/**
* Called when all the digits of the passcode has been entered
*
* #param passcode - The entered passcode
*/
void onPasscodeEntered(String passcode);
}
static class SavedState extends BaseSavedState {
public static final Creator<SavedState> CREATOR =
new Creator<SavedState>() {
#Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
#Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
String editTextValue;
public SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel source) {
super(source);
editTextValue = source.readString();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(editTextValue);
}
}
class DigitView extends View {
private Paint mOuterPaint, mInnerPaint;
private int mPosition = 0;
public DigitView(Context context, int position) {
this(context);
mPosition = position;
}
public DigitView(Context context) {
this(context, null);
}
public DigitView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DigitView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
void init() {
setWillNotDraw(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
mOuterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mOuterPaint.setAlpha(255);
mOuterPaint.setDither(true);
mOuterPaint.setStyle(Paint.Style.STROKE);
mOuterPaint.setStrokeWidth(mOuterStrokeWidth);
mOuterPaint.setStrokeCap(Paint.Cap.ROUND);
mOuterPaint.setStrokeJoin(Paint.Join.ROUND);
mOuterPaint.setShadowLayer(2, 0, 0, Color.parseColor("#B4999999"));
mInnerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mInnerPaint.setAlpha(255);
mInnerPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mInnerPaint.setStrokeWidth(mInnerStrokeWidth);
mInnerPaint.setStrokeCap(Paint.Cap.ROUND);
mInnerPaint.setStrokeJoin(Paint.Join.ROUND);
mInnerPaint.setColor(mInnerColor);
invalidate();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(mDigitWidth, mDigitWidth);
}
#Override
protected void onDraw(Canvas canvas) {
float center = getWidth() / 2;
if (isSelected()) {
mOuterPaint.setColor(mHighlightedColor);
} else {
mOuterPaint.setColor(mControlColor);
}
canvas.drawColor(Color.TRANSPARENT);
canvas.drawCircle(center, center, mDigitRadius, mOuterPaint);
if (mEditText.getText().length() > mPosition) {
canvas.drawCircle(center, center, mDigitInnerRadius, mInnerPaint);
}
}
}
Now, I want to open number keyboard as soon as dialog shows up. For this, I have a method requestToShowKeyboard() in PasscodeView.java to open keyboard.
But, keyboard doesn't open when dialog shows up. Below is the code I wrote inside onViewCreated().
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mPasscodeView.requestToShowKeyboard();
}
This is how I used PasscodeView in dialog fragment layout:
<com.via.android.customview.PasscodeView
android:id="#+id/edtOptCode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="#dimen/dimen_10_dp"
android:background="#null"
android:gravity="center"
android:padding="#dimen/dimen_8_dp"
passcodeView:digitColorBorder="#FFFFFF"
passcodeView:digitColorFilled="#9f9f9f"
passcodeView:digitRadius="12dp"
passcodeView:numDigits="6" />
If anyone can help me with this.
Solved: Solution to my problem has been turned out to this as below:
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mPasscodeView.post(new Runnable() {
#Override
public void run() {
mPasscodeView.requestToShowKeyboard();
}
});
}
Instead of calling in onViewCreated(), try calling like
mPasscodeView.post(new Runnable() {
#Override
public void run() {
mPasscodeView.requestToShowKeyboard();
}
});
So this will add the runnable to the queue to execute in next pass.

GridLayout with view dynamic get row/column

I just followed this tutorial, to create a custom View as an item of a GridLayout.
That's my CustomView
public class RowView extends View{
boolean touchOn;
boolean mDownTouch = false;
private OnToggledListener toggledListener;
int _IdRow = 0;
int _IdColumn = 0;
public RowView(Context context, int Rows, int Columns) {
super(context);
this._IdRow = Rows;
this._IdColumn = Columns;
init();
}
public RowView(Context context) {
super(context);
init();
}
public RowView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RowView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
touchOn = false;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
}
#Override
protected void onDraw(Canvas canvas) {
if (touchOn) {
canvas.drawColor(Color.RED);
} else {
canvas.drawColor(Color.GRAY);
}
}
//onClick not possible to use on custom View so, onTouchEvent is the solution
#Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
//if Click
case MotionEvent.ACTION_DOWN:
touchOn = !touchOn;
invalidate();
if(toggledListener != null){
toggledListener.OnToggled(this, touchOn);
}
mDownTouch = true;
return true;
case MotionEvent.ACTION_UP:
if (mDownTouch) {
mDownTouch = false;
performClick();
return true;
}
}
return false;
}
#Override
public boolean performClick() {
super.performClick();
return true;
}
public void setOnToggledListener(OnToggledListener listener){
toggledListener = listener;
}
public int get_IdRow() {
return _IdRow;
}
public int get_IdColumn() {
return _IdColumn;
}
On this class I can detect when user clicks on an item of GridLayout and change it to another color, that's ok.
But the problem comes at the time to create this :
This is my MainActivity where I show the GridLayout :
int numOfCol = mGridLayout.getColumnCount();
int numOfRow = mGridLayout.getRowCount();
mRowViews = new RowView[numOfCol*numOfRow];
for(int yPos=0; yPos<numOfRow; yPos++){
for(int xPos=0; xPos<numOfCol; xPos++){
RowView tView = new RowView(this, xPos, yPos);
tView.setOnToggledListener(this);
mRowViews[yPos*numOfCol + xPos] = tView;
mGridLayout.addView(tView);
}
}
mGridLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener(){
#Override
public void onGlobalLayout() {
final int MARGIN = 5;
int pWidth = mGridLayout.getWidth();
int pHeight = mGridLayout.getHeight();
int numOfCol = mGridLayout.getColumnCount();
int numOfRow = mGridLayout.getRowCount();
int w = pWidth/numOfCol;
int h = pHeight/numOfRow;
for(int yPos=0; yPos<numOfRow; yPos++){
for(int xPos=0; xPos<numOfCol; xPos++){
GridLayout.LayoutParams params =
(GridLayout.LayoutParams)mRowViews[yPos*numOfCol + xPos].getLayoutParams();
params.width = w - 2*MARGIN;
params.height = h - 2*MARGIN;
params.setMargins(MARGIN, MARGIN, MARGIN, MARGIN);
mRowViews[yPos*numOfCol + xPos].setLayoutParams(params);
}
}
}});
Also there is a method of the Interface OnToggledListener that gives to me the row and column of my GridLayout when an item of it is clicked :
#Override
public void OnToggled(MyView v, boolean touchOn) {
//get the id string
String idString = v.get_IdRow() + ":" + v.get_IdColumn();
}
I'd like to avoid to create that mGridLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() because it fills on the screen thing that I don't want... I tried to put GridLayout 6x6 with android:layout_height="400dp" and it only show 3x3 and this is the LogCat message
D/android.widget.GridLayout: vertical constraints: y6-y0>=1749, y6-y5<=291, y5-y4<=291, y4-y3<=291, y3-y2<=291, y2-y1<=291, y1-y0<=291 are inconsistent; permanently removing: y6-y5<=291.
I'd like to do something like GridLayout[row][colum] to get the color of background and then do stuff, but I'm not able to find this solution.
For simplifying, you can implement a custom Board view wrapping the GridLayout and related logic. Below I report a possible approach.
Expectation here is to have an ItemView for representing one single cell in the board.
public class Board extends FrameLayout implements View.OnClickListener {
private GridLayout mGridView;
private int mRowsCount;
private int mColsCount;
private int mCellSpace;
private OnItemClickListener mOnItemClickListener;
public Board(Context context) {
super(context);
init(context, null);
}
// other constructors
private void init(Context context, AttributeSet attrs) {
// default values
mRowsCount = 1;
mColsCount = 1;
View layout = inflate(getContext(), R.layout.view_lights_board, null);
mGridView = (GridLayout) layout.findViewById(R.id.view_grid);
mGridView.setRowCount(mRowsCount);
mGridView.setColumnCount(mColsCount);
mGridView.post(new Runnable() {
#Override
public void run() {
int width = getMeasuredWidth() / getColumnsCount();
int height = getMeasuredHeight() / getRowsCount();
for (int i = 0; i < getRowsCount(); i++) {
for (int j = 0; j < getColumnsCount(); j++) {
GridLayout.LayoutParams params = (GridLayout.LayoutParams)
getChildAt(i, j).getLayoutParams();
params.width = width;
params.height = height;
getChildAt(i, j).setLayoutParams(params);
}
}
}
});
addView(layout);
}
// this method allows to dinamically create grid
public void buildChildren(int rowsCount, int colsCount) {
mRowsCount = rowsCount;
mColsCount = colsCount;
mGridView.setRowCount(mRowsCount);
mGridView.setColumnCount(mColsCount);
buildChildren();
}
public void buildChildren() {
for (int i = 0; i < getRowsCount(); i++) {
for (int j = 0; j < getColumnsCount(); j++) {
ItemView view = new ItemView(getContext(), i, j);
view.setOnClickListener(this);
mGridView.addView(view);
}
}
}
public void setOnItemClickListener(OnItemClickListener listener) {
mOnItemClickListener = listener;
}
public ItemView getChildAt(int rowIndex, int columnIndex) {
int index = (getColumnsCount() * rowIndex) + columnIndex;
return (ItemView) mGridView.getChildAt(index);
}
public boolean isTouchOn(int rowIndex, int columnIndex) {
return getChildAt(rowIndex, columnIndex).isTouchOn();
}
public int getColumnsCount() {
return mGridView.getColumnCount();
}
public int getRowsCount() {
return mGridView.getRowCount();
}
#Override
public void onClick(View v) {
if (v instanceof ItemView) {
ItemView view = (ItemView) v;
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(view);
}
}
}
public interface OnItemClickListener {
void onItemClick(ItemView view);
}
}
In your Activity layout you will have something like this (here I assume your app package is com.android.example):
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.android.example.Board
android:id="#+id/grid"
android:layout_width="match_parent"
android:layout_height="400dp" />
</FrameLayout>
And this is possible implementation of the Activity:
public class MainActivity extends AppCompatActivity implements LightsOutBoard.OnItemClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Board board = (Board) findViewById(R.id.grid);
board.setOnItemClickListener(this);
board.buildChildren(3, 3);
}
#Override
public void onItemClick(ItemView view) {
String text = view.getRowIndex() + " - " + view.getColumnIndex();
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
}
Hope this could help.

Categories

Resources