I am getting null pointer on back press of activity where I have used the custom view. Where am I doing wrong?? Below is my custom view class:
public class PuzzleBoardView extends View implements ViewTreeObserver.OnGlobalLayoutListener {
public static final int NUM_SHUFFLE_STEPS = 40;
Comparator<PuzzleBoard> comparator = new PuzzleBoardComparator();
PriorityQueue<PuzzleBoard> queue = new PriorityQueue<>(9999, comparator);
private PuzzleActivity activity;
private PuzzleBoard puzzleBoard;
private ArrayList<PuzzleBoard> animation;
private Random random = new Random();
private Bitmap imgBitmap;
public PuzzleBoardView(Context context) {
super(context);
setMinimumWidth(50);
activity = (PuzzleActivity) context;
animation = null;
}
public void initialize(final Bitmap imageBitmap, Activity parent) {
final int width = getWidth();
imgBitmap = imageBitmap;
Log.d("PuzzleBoardView", "initialize: width=== " + width);
addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
#Override
public void onViewAttachedToWindow(View v) {
Log.d("PuzzleBoardView", "onViewAttachedToWindow=== " + width);
puzzleBoard = new PuzzleBoard(imgBitmap, getWidth());
shuffle();
}
#Override
public void onViewDetachedFromWindow(View v) {
Log.d("PuzzleBoardView", "onViewDetachedFromWindow=== ");
onDetachedFromWindow();
}
});
}
public void clearView() {
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d("TAG", "onDraw: =====");
if (puzzleBoard != null) {
Log.d("TAG", "onDraw:111 =====");
if (animation != null && animation.size() > 0) {
puzzleBoard = animation.remove(0);
puzzleBoard.draw(canvas);
if (animation.size() == 0) {
animation = null;
puzzleBoard.reset();
Toast toast = Toast.makeText(activity, "Solved! ", Toast.LENGTH_LONG);
toast.show();
} else {
this.postInvalidateDelayed(500);
}
} else {
puzzleBoard.draw(canvas);
}
}
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.d("PuzzleBoardView", "onDetachedFromWindow=== ");
getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
public void shuffle() {
if (animation == null && puzzleBoard != null) {
// Do something. Then:
ArrayList<PuzzleBoard> boards;
for (int i = 0; i <= NUM_SHUFFLE_STEPS; i++) {
boards = puzzleBoard.neighbours();
puzzleBoard = boards.get(random.nextInt(boards.size()));
}
puzzleBoard.reset();
invalidate();
queue.clear();
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (animation == null && puzzleBoard != null) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (puzzleBoard.click(event.getX(), event.getY())) {
invalidate();
if (puzzleBoard.resolved()) {
/*Toast toast = Toast.makeText(activity, "Congratulations!", Toast.LENGTH_LONG);
toast.show();*/
activity.puzzleSolved();
}
return true;
}
}
}
return super.onTouchEvent(event);
}
public void solve() {
puzzleBoard.steps = 0;
puzzleBoard.previousBoard = null;
queue.add(puzzleBoard);
PuzzleBoard prev = null;
ArrayList<PuzzleBoard> solution = new ArrayList<>();
while (!queue.isEmpty()) {
PuzzleBoard lowest = queue.poll();
if (lowest.priority() - lowest.steps != 0) {
for (PuzzleBoard toAdd : lowest.neighbours()) {
if (!toAdd.equals(prev)) {
queue.add(toAdd);
}
}
prev = lowest;
} else {
solution.add(lowest);
while (lowest != null) {
if (lowest.getPreviousBoard() == null) {
break;
}
solution.add(lowest.getPreviousBoard());
lowest = lowest.getPreviousBoard();
}
Collections.reverse(solution);
animation = solution;
invalidate();
break;
}
}
}
public PuzzleBoard getPuzzleBoard() {
return puzzleBoard;
}
public void setPuzzleBoard(PuzzleBoard puzzleBoard) {
this.puzzleBoard = puzzleBoard;
}
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
Log.d("PuzzleBoardView", "onAttachedToWindow: width=== " + getWidth());
puzzleBoard = new PuzzleBoard(imgBitmap, getWidth());
shuffle();
}
}
class PuzzleBoardComparator implements Comparator<PuzzleBoard> {
#Override
public int compare(PuzzleBoard first, PuzzleBoard second) {
if (first.priority() == second.priority()) {
return 0;
} else if (first.priority() < second.priority()) {
return -1;
} else {
return 1;
}
}
}
Here is my Exception
java.lang.NullPointerException: Attempt to invoke interface method 'void android.view.View$OnAttachStateChangeListener.onViewDetachedFromWindow(android.view.View)' on a null object reference
Change your code like below.
public PuzzleBoardView(Context context) {
super(context);
setMinimumWidth(50);
activity = (PuzzleActivity) context;
animation = null;
if(activity!=null)
initialize();
}
and remove initialize method from onCreate()
Related
I'm a beginner of Android. I'm trying to control it by adding several dynamic views. What I want to do is add, delete, and bringfront view work. But I'm not doing it. I attach my code. The biggest problem I face the most is the following.
I'd like to create two views and then do a bringfront, but it only applies to the most late created views.
I want you to tell me how to solve it.
public class Fit_Me_page extends AppCompatActivity implements View.OnTouchListener {
private RecyclerView fit_me_recyclerview;
private ArrayList<Fit_Me_Array> fit_me_arrays;
private Fit_Me_Adapter fit_me_adapter;
Fit_Me_Category_Array fit_me_all_category_array;
int category_number = 0;
ConstraintLayout fit_me_constraintLayout;
private ConstraintSet applyConstraintSet = new ConstraintSet();
TextView textView, textView2;
ImageView imageView;
ImageView imageView2;
ImageView testView;
ArrayList<String> category_array_1 = new ArrayList<>();
ArrayList<String> category_array_2;
ImageView show_cloth_information_btn, cloth_size_up_btn, cloth_size_down_btn,
compare_my_size_btn, cloth_bring_front_btn, cloth_send_back_btn, cloth_delete_btn;
int number = 0;
int i = 11;
#SuppressLint("ClickableViewAccessibility")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fit_me_page);
show_cloth_information_btn = findViewById(R.id.show_cloth_information);
cloth_size_up_btn = findViewById(R.id.cloth_size_up);
cloth_size_down_btn = findViewById(R.id.cloth_size_down);
compare_my_size_btn = findViewById(R.id.check_my_size);
cloth_bring_front_btn = findViewById(R.id.front_image);
cloth_send_back_btn = findViewById(R.id.back_image);
cloth_delete_btn = findViewById(R.id.delete_image);
fit_me_recyclerview = findViewById(R.id.fit_me_recyclerview);
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3);
fit_me_arrays = new ArrayList<>();
fit_me_adapter = new Fit_Me_Adapter(this, fit_me_arrays);
fit_me_recyclerview.setAdapter(fit_me_adapter);
fit_me_recyclerview.addItemDecoration(new grid_view_padding(this));
fit_me_recyclerview.setLayoutManager(gridLayoutManager);
fit_me_constraintLayout = findViewById(R.id.fit_me_ConstraintLayout);
fit_me_all_category_array = new Fit_Me_Category_Array();
testView = new ImageView(Fit_Me_page.this);
fit_me_constraintLayout.addView(testView);
imageView2 = findViewById(R.id.imageView2);
fit_me_adapter.setOnItemClickListener(new Fit_Me_Adapter.OnItemClickListener() {
#Override
public void onItemClick(int position) {
if (position == 1 && category_number == 0) {
fit_me_arrays.clear();
for (int i = 0; i < fit_me_all_category_array.categoryOuter.size(); i++) {
Fit_Me_Array fit_me_array = new Fit_Me_Array(fit_me_all_category_array.categoryOuter.get(i));
fit_me_arrays.add(fit_me_array);
}
category_number++;
fit_me_adapter.notifyDataSetChanged();
} else if (position == 1 && category_number == 1) {
imageView = new ImageView(Fit_Me_page.this);
imageView.setImageResource(R.drawable.color_wheel);
// imageView.setLayoutParams(layoutParams);
imageView.bringToFront();
imageView.setOnTouchListener(Fit_Me_page.this::onTouch);
//imageView.setOnLongClickListener(Fit_Me_page.this::onLongClick);
i++;
imageView.setId(i);
fit_me_constraintLayout.addView(imageView);
} else if (position == 2 && category_number == 1) {
// ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(M,700);
imageView = new ImageView(Fit_Me_page.this);
imageView.setImageResource(R.drawable.camera_button);
// imageView.setLayoutParams(layoutParams);
imageView.bringToFront();
imageView.setOnTouchListener(Fit_Me_page.this::onTouch);
//imageView.setOnLongClickListener(Fit_Me_page.this::onLongClick);
i++;
imageView.setId(i);
fit_me_constraintLayout.addView(imageView);
} else if (position == 0 && category_number == 1) {
fit_me_arrays.clear();
for (int i = 0; i < fit_me_all_category_array.categoryAll.size(); i++) {
Fit_Me_Array fit_me_array = new Fit_Me_Array(fit_me_all_category_array.categoryAll().get(i));
fit_me_arrays.add(fit_me_array);
}
fit_me_adapter.notifyDataSetChanged();
category_number--;
}
}
});
}
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onResume() {
super.onResume();
show_cloth_information_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
imageView2.bringToFront();
}
});
cloth_size_up_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
cloth_size_down_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
compare_my_size_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
cloth_bring_front_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
testView = fit_me_constraintLayout.findFocus().findViewById(number);
testView.bringToFront();
}
});
cloth_send_back_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
cloth_delete_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
#Override
protected void onPause() {
super.onPause();
}
#Override
protected void onStop() {
super.onStop();
}
float oldXvalue;
float oldYvalue;
#Override
public boolean onTouch(View v, MotionEvent event) {
int parentWidth = ((ViewGroup) v.getParent()).getWidth(); // 부모 View 의 Width
int parentHeight = ((ViewGroup) v.getParent()).getHeight(); // 부모 View 의 Height
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// 뷰 누름
Log.d("바로?", "onTouch: " + "다운");
oldXvalue = event.getX();
oldYvalue = event.getY();
number = v.getId();
testView.setId(number);
return true;
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
Log.d("바로?", "onTouch: " + "무브");
v.setX(v.getX() + (event.getX()) - oldXvalue);
v.setY(v.getY() + (event.getY()) - oldYvalue);
Log.d("viewTest", "onTouch: ");
Log.d("viewTest", "onTouch: ");
} else if (event.getAction() == MotionEvent.ACTION_UP) {
if (v.getX() < 0) {
v.setX(0);
} else if ((v.getX() + v.getWidth()) > parentWidth) {
v.setX(parentWidth - v.getWidth());
}
if (v.getY() < 0) {
v.setY(0);
} else if ((v.getY() + v.getHeight()) > parentHeight) {
v.setY(parentHeight - v.getHeight());
}
return true;
}
return true;
}
}
fit_me_constraintLayout.addView(imageView);
You had used this to add view correct..
Layout will add view just like list 1 after other, so you just need to remove that particular view and add it again, it will be on top.
So where ever you need to perform brintToFront.
fit_me_constraintLayout.removeView(imageView);
fit_me_constraintLayout.addView(imageView);
AFTER EDIT
cloth_bring_front_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
testView = fit_me_constraintLayout.findFocus().findViewById(number);
if(testView !=null){
fit_me_constraintLayout.removeView(testView );
fit_me_constraintLayout.addView(testView );}
}
});
Let me know if that words
I am making a custom edittext to enter mobile numbers. Here is the code
public class PinEntryEditText extends android.support.v7.widget.AppCompatEditText {
private static final String XML_NAMESPACE_ANDROID = "http://schemas.android.com/apk/res/android";
protected String mMask = null;
protected StringBuilder mMaskChars = null;
protected String mSingleCharHint = null;
protected int mAnimatedType = 0;
protected float mSpace = 24; //24 dp by default, space between the lines
protected float mCharSize;
protected float mNumChars = 4;
protected float mTextBottomPadding = 8; //8dp by default, height of the text from our lines
protected int mMaxLength = 4;
protected RectF[] mLineCoords;
protected float[] mCharBottom;
protected Paint mCharPaint;
protected Paint mLastCharPaint;
protected Paint mSingleCharPaint;
protected Drawable mPinBackground;
protected Rect mTextHeight = new Rect();
protected boolean mIsDigitSquare = false;
protected View.OnClickListener mClickListener;
protected OnPinEnteredListener mOnPinEnteredListener = null;
protected float mLineStroke = 1; //1dp by default
protected float mLineStrokeSelected = 2; //2dp by default
protected Paint mLinesPaint;
protected boolean mAnimate = false;
protected boolean mHasError = false;
protected ColorStateList mOriginalTextColors;
protected int[][] mStates = new int[][]{
new int[]{android.R.attr.state_selected}, // selected
new int[]{android.R.attr.state_active}, // error
new int[]{android.R.attr.state_focused}, // focused
new int[]{-android.R.attr.state_focused}, // unfocused
};
protected int[] mColors = new int[]{
Color.GREEN,
Color.RED,
Color.BLACK,
Color.GRAY
};
protected ColorStateList mColorStates = new ColorStateList(mStates, mColors);
public PinEntryEditText(Context context) {
super(context);
}
public PinEntryEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public PinEntryEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// this(context, attrs, android.R.attr.editTextStyle);
init(context, attrs);
}
public void setMaxLength(final int maxLength) {
mMaxLength = maxLength;
mNumChars = maxLength;
setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});
setText(null);
invalidate();
}
private void init(Context context, AttributeSet attrs) {
float multi = context.getResources().getDisplayMetrics().density;
mLineStroke = multi * mLineStroke;
mLineStrokeSelected = multi * mLineStrokeSelected;
mSpace = multi * mSpace; //convert to pixels for our density
mTextBottomPadding = multi * mTextBottomPadding; //convert to pixels for our density
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PinEntryEditText, 0, 0);
try {
TypedValue outValue = new TypedValue();
ta.getValue(R.styleable.PinEntryEditText_pinAnimationType, outValue);
mAnimatedType = outValue.data;
mMask = ta.getString(R.styleable.PinEntryEditText_pinCharacterMask);
mSingleCharHint = ta.getString(R.styleable.PinEntryEditText_pinRepeatedHint);
mLineStroke = ta.getDimension(R.styleable.PinEntryEditText_pinLineStroke, mLineStroke);
mLineStrokeSelected = ta.getDimension(R.styleable.PinEntryEditText_pinLineStrokeSelected, mLineStrokeSelected);
mSpace = ta.getDimension(R.styleable.PinEntryEditText_pinCharacterSpacing, mSpace);
mTextBottomPadding = ta.getDimension(R.styleable.PinEntryEditText_pinTextBottomPadding, mTextBottomPadding);
mIsDigitSquare = ta.getBoolean(R.styleable.PinEntryEditText_pinBackgroundIsSquare, mIsDigitSquare);
mPinBackground = ta.getDrawable(R.styleable.PinEntryEditText_pinBackgroundDrawable);
ColorStateList colors = ta.getColorStateList(R.styleable.PinEntryEditText_pinLineColors);
if (colors != null) {
mColorStates = colors;
}
} finally {
ta.recycle();
}
mCharPaint = new Paint(getPaint());
mLastCharPaint = new Paint(getPaint());
mSingleCharPaint = new Paint(getPaint());
mLinesPaint = new Paint(getPaint());
mLinesPaint.setStrokeWidth(mLineStroke);
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.colorControlActivated,
outValue, true);
int colorSelected = outValue.data;
mColors[0] = colorSelected;
int colorFocused = isInEditMode() ? Color.GRAY : ContextCompat.getColor(context, R.color.pin_normal);
mColors[1] = colorFocused;
int colorUnfocused = isInEditMode() ? Color.GRAY : ContextCompat.getColor(context, R.color.pin_normal);
mColors[2] = colorUnfocused;
setBackgroundResource(0);
mMaxLength = attrs.getAttributeIntValue(XML_NAMESPACE_ANDROID, "maxLength", 4);
mNumChars = mMaxLength;
//Disable copy paste
super.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
});
// When tapped, move cursor to end of text.
super.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setSelection(getText().length());
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
});
super.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
setSelection(getText().length());
return true;
}
});
//If input type is password and no mask is set, use a default mask
if ((getInputType() & InputType.TYPE_TEXT_VARIATION_PASSWORD) == InputType.TYPE_TEXT_VARIATION_PASSWORD && TextUtils.isEmpty(mMask)) {
mMask = "\u25CF";
} else if ((getInputType() & InputType.TYPE_NUMBER_VARIATION_PASSWORD) == InputType.TYPE_NUMBER_VARIATION_PASSWORD && TextUtils.isEmpty(mMask)) {
mMask = "\u25CF";
}
if (!TextUtils.isEmpty(mMask)) {
mMaskChars = getMaskChars();
}
//Height of the characters, used if there is a background drawable
getPaint().getTextBounds("|", 0, 1, mTextHeight);
mAnimate = mAnimatedType > -1;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mOriginalTextColors = getTextColors();
if (mOriginalTextColors != null) {
mLastCharPaint.setColor(mOriginalTextColors.getDefaultColor());
mCharPaint.setColor(mOriginalTextColors.getDefaultColor());
mSingleCharPaint.setColor(getCurrentHintTextColor());
}
int availableWidth = getWidth() - ViewCompat.getPaddingEnd(this) - ViewCompat.getPaddingStart(this);
if (mSpace < 0) {
mCharSize = (availableWidth / (mNumChars * 2 - 1));
} else {
mCharSize = (availableWidth - (mSpace * (mNumChars - 1))) / mNumChars;
}
mLineCoords = new RectF[(int) mNumChars];
mCharBottom = new float[(int) mNumChars];
int startX;
int bottom = getHeight() - getPaddingBottom();
int rtlFlag;
final boolean isLayoutRtl = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL;
if (isLayoutRtl) {
rtlFlag = -1;
startX = (int) (getWidth() - ViewCompat.getPaddingStart(this) - mCharSize);
} else {
rtlFlag = 1;
startX = ViewCompat.getPaddingStart(this);
}
for (int i = 0; i < mNumChars; i++) {
mLineCoords[i] = new RectF(startX, bottom, startX + mCharSize, bottom);
if (mPinBackground != null) {
if (mIsDigitSquare) {
mLineCoords[i].top = getPaddingTop();
mLineCoords[i].right = startX + mLineCoords[i].height();
} else {
mLineCoords[i].top -= mTextHeight.height() + mTextBottomPadding * 2;
}
}
if (mSpace < 0) {
startX += rtlFlag * mCharSize * 2;
} else {
startX += rtlFlag * (mCharSize + mSpace);
}
mCharBottom[i] = mLineCoords[i].bottom - mTextBottomPadding;
}
}
#Override
public void setOnClickListener(View.OnClickListener l) {
mClickListener = l;
}
#Override
public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
throw new RuntimeException("setCustomSelectionActionModeCallback() not supported.");
}
#Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
CharSequence text = getFullText();
int textLength = text.length();
float[] textWidths = new float[textLength];
getPaint().getTextWidths(text, 0, textLength, textWidths);
float hintWidth = 0;
if (mSingleCharHint != null) {
float[] hintWidths = new float[mSingleCharHint.length()];
getPaint().getTextWidths(mSingleCharHint, hintWidths);
for (float i : hintWidths) {
hintWidth += i;
}
}
for (int i = 0; i < mNumChars; i++) {
//If a background for the pin characters is specified, it should be behind the characters.
if (mPinBackground != null) {
updateDrawableState(i < textLength, i == textLength);
mPinBackground.setBounds((int) mLineCoords[i].left, (int) mLineCoords[i].top, (int) mLineCoords[i].right, (int) mLineCoords[i].bottom);
mPinBackground.draw(canvas);
}
float middle = mLineCoords[i].left + mCharSize / 2;
if (textLength > i) {
if (!mAnimate || i != textLength - 1) {
canvas.drawText(text, i, i + 1, middle - textWidths[i] / 2, mCharBottom[i], mCharPaint);
} else {
canvas.drawText(text, i, i + 1, middle - textWidths[i] / 2, mCharBottom[i], mLastCharPaint);
}
} else if (mSingleCharHint != null) {
canvas.drawText(mSingleCharHint, middle - hintWidth / 2, mCharBottom[i], mSingleCharPaint);
}
//The lines should be in front of the text (because that's how I want it).
if (mPinBackground == null) {
updateColorForLines(i <= textLength);
canvas.drawLine(mLineCoords[i].left, mLineCoords[i].top, mLineCoords[i].right, mLineCoords[i].bottom, mLinesPaint);
}
}
}
private CharSequence getFullText() {
if (mMask == null) {
return getText();
} else {
return getMaskChars();
}
}
private StringBuilder getMaskChars() {
if (mMaskChars == null) {
mMaskChars = new StringBuilder();
}
int textLength = getText().length();
while (mMaskChars.length() != textLength) {
if (mMaskChars.length() < textLength) {
mMaskChars.append(mMask);
} else {
mMaskChars.deleteCharAt(mMaskChars.length() - 1);
}
}
return mMaskChars;
}
private int getColorForState(int... states) {
return mColorStates.getColorForState(states, Color.GRAY);
}
/**
* #param hasTextOrIsNext Is the color for a character that has been typed or is
* the next character to be typed?
*/
protected void updateColorForLines(boolean hasTextOrIsNext) {
if (mHasError) {
mLinesPaint.setColor(getColorForState(android.R.attr.state_active));
} else if (isFocused()) {
mLinesPaint.setStrokeWidth(mLineStrokeSelected);
mLinesPaint.setColor(getColorForState(android.R.attr.state_focused));
if (hasTextOrIsNext) {
mLinesPaint.setColor(getColorForState(android.R.attr.state_selected));
}
} else {
mLinesPaint.setStrokeWidth(mLineStroke);
mLinesPaint.setColor(getColorForState(-android.R.attr.state_focused));
}
}
protected void updateDrawableState(boolean hasText, boolean isNext) {
if (mHasError) {
mPinBackground.setState(new int[]{android.R.attr.state_active});
} else if (isFocused()) {
mPinBackground.setState(new int[]{android.R.attr.state_focused});
if (isNext) {
mPinBackground.setState(new int[]{android.R.attr.state_focused, android.R.attr.state_selected});
} else if (hasText) {
mPinBackground.setState(new int[]{android.R.attr.state_focused, android.R.attr.state_checked});
}
} else {
mPinBackground.setState(new int[]{-android.R.attr.state_focused});
}
}
public void setError(boolean hasError) {
mHasError = hasError;
}
public boolean isError() {
return mHasError;
}
/**
* Request focus on this PinEntryEditText
*/
public void focus() {
requestFocus();
// Show keyboard
InputMethodManager inputMethodManager = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.showSoftInput(this, 0);
}
#Override
protected void onTextChanged(CharSequence text, final int start, int lengthBefore, final int lengthAfter) {
setError(false);
if (mLineCoords == null || !mAnimate) {
if (mOnPinEnteredListener != null && text.length() == mMaxLength) {
mOnPinEnteredListener.onPinEntered(text);
}
return;
}
if (mAnimatedType == -1) {
invalidate();
return;
}
if (lengthAfter > lengthBefore) {
if (mAnimatedType == 0) {
animatePopIn();
} else {
animateBottomUp(text, start);
}
}
}
private void animatePopIn() {
ValueAnimator va = ValueAnimator.ofFloat(1, getPaint().getTextSize());
va.setDuration(200);
va.setInterpolator(new OvershootInterpolator());
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
mLastCharPaint.setTextSize((Float) animation.getAnimatedValue());
PinEntryEditText.this.invalidate();
}
});
if (getText().length() == mMaxLength && mOnPinEnteredListener != null) {
va.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
mOnPinEnteredListener.onPinEntered(getText());
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
}
va.start();
}
private void animateBottomUp(CharSequence text, final int start) {
mCharBottom[start] = mLineCoords[start].bottom - mTextBottomPadding;
ValueAnimator animUp = ValueAnimator.ofFloat(mCharBottom[start] + getPaint().getTextSize(), mCharBottom[start]);
animUp.setDuration(300);
animUp.setInterpolator(new OvershootInterpolator());
animUp.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
Float value = (Float) animation.getAnimatedValue();
mCharBottom[start] = value;
PinEntryEditText.this.invalidate();
}
});
mLastCharPaint.setAlpha(255);
ValueAnimator animAlpha = ValueAnimator.ofInt(0, 255);
animAlpha.setDuration(300);
animAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
mLastCharPaint.setAlpha(value);
}
});
AnimatorSet set = new AnimatorSet();
if (text.length() == mMaxLength && mOnPinEnteredListener != null) {
set.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
mOnPinEnteredListener.onPinEntered(getText());
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
}
set.playTogether(animUp, animAlpha);
set.start();
}
public void setAnimateText(boolean animate) {
mAnimate = animate;
}
public void setOnPinEnteredListener(OnPinEnteredListener l) {
mOnPinEnteredListener = l;
}
public interface OnPinEnteredListener {
void onPinEntered(CharSequence str);
}
}
Following is the xml
<com.cartoon.customLayout.PinEntryEditText
android:id="#+id/et_activity_mobile_pinEntryEditText"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:background="#null"
android:cursorVisible="true"
android:digits="1234567890"
android:focusable="true"
android:imeOptions="actionDone"
android:inputType="number|phone"
android:maxLength="10"
android:textColor="#android:color/white"
android:textIsSelectable="true"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.40"
app:pinAnimationType="fromBottom"
app:pinBackgroundDrawable="#drawable/bg_pin"
app:pinCharacterSpacing="4dp" />
Suppose the user enters his mobile number and the second digit entered is wrong then the problem is, he/she has to erase the entered characters leading to the second character for a change.
I went through the following posts but they are of no help
Custom EditText is not showing keyboard on focus
Custom Android pin code entry widget
https://github.com/ChaosLeong/PinView
Setting focusable, clickable or focusableInTouchMode does not work. Tried both in XML and code.
The below library does solve my problem but it has some other problem for which I have raised an issue
https://github.com/mukeshsolanki/android-otpview-pinview
Issue: https://github.com/mukeshsolanki/android-otpview-pinview/issues/26
Of course I could take 10 edittext and achieve the result which I want but that is not the right way and I will resort to that option in case I am not able to find the right solution to this one.
The answer is in your java code. As mentioned in the comment just remove this from the init() method.
// When tapped, move cursor to end of text.
super.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setSelection(getText().length());
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
});
Please make the following changes:
In your PinEntryEditText class:
// When tapped, move cursor to end of text.
super.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//setSelection(getText().length());
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
});
I think setSelection(getText().length()); was setting selection to the end of the EditText no matter where the click even occured.
And in your XML, do these: android:cursorVisible="true" and android:textIsSelectable="true"
I want to achieve Single RadioGroup like below image for blood group selection.
How can this be done?
I created my own RadioGridLayout which include RadioGroup code and extends GridLayout.
You can copy this code. For me working well.
After you can use this layout in your xml and customize like grid layout.
For R.styleable.RadioGridLayout_checked I used code like this:
<resources>
<declare-styleable name="RadioGridLayout">
<attr name="checked" format="integer" />
</declare-styleable>
</resources>
public class RadioGridLayout extends GridLayout {
private int mCheckedId = -1;
private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
private boolean mProtectFromCheckedChange = false;
private OnCheckedChangeListener mOnCheckedChangeListener;
private PassThroughHierarchyChangeListener mPassThroughListener;
private void setCheckedId(#IdRes int id) {
mCheckedId = id;
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
}
AutofillManager afm = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
afm = getContext().getSystemService(AutofillManager.class);
}
if (afm != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
afm.notifyValueChanged(this);
}
}
}
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
mOnCheckedChangeListener = listener;
}
public interface OnCheckedChangeListener {
void onCheckedChanged(RadioGridLayout group, #IdRes int checkedId);
}
private int mInitialCheckedId = View.NO_ID;
public RadioGridLayout(Context context) {
super(context);
setOrientation(VERTICAL);
init();
}
public RadioGridLayout(Context context, AttributeSet attrs) {
super(context, attrs);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) {
setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES);
}
}
TypedArray attributes = context.obtainStyledAttributes(
attrs,
R.styleable.RadioGridLayout,
R.attr.radioButtonStyle, 0);
int value = attributes.getResourceId(R.styleable.RadioGridLayout_checked, View.NO_ID);
if (value != View.NO_ID) {
mCheckedId = value;
mInitialCheckedId = value;
}
attributes.recycle();
init();
}
private void init() {
mChildOnCheckedChangeListener = new CheckedStateTracker();
mPassThroughListener = new PassThroughHierarchyChangeListener();
super.setOnHierarchyChangeListener(mPassThroughListener);
}
#Override
public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
mPassThroughListener.mOnHierarchyChangeListener = listener;
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
if (mCheckedId != -1) {
mProtectFromCheckedChange = true;
setCheckedStateForView(mCheckedId, true);
mProtectFromCheckedChange = false;
setCheckedId(mCheckedId);
}
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (child instanceof RadioButton) {
final RadioButton button = (RadioButton) child;
if (button.isChecked()) {
mProtectFromCheckedChange = true;
if (mCheckedId != -1) {
setCheckedStateForView(mCheckedId, false);
}
mProtectFromCheckedChange = false;
setCheckedId(button.getId());
}
}
super.addView(child, index, params);
}
public void check(#IdRes int id) {
if (id != -1 && (id == mCheckedId)) {
return;
}
if (mCheckedId != -1) {
setCheckedStateForView(mCheckedId, false);
}
if (id != -1) {
setCheckedStateForView(id, true);
}
setCheckedId(id);
}
private void setCheckedStateForView(int viewId, boolean checked) {
View checkedView = findViewById(viewId);
if (checkedView != null && checkedView instanceof RadioButton) {
((RadioButton) checkedView).setChecked(checked);
}
}
#IdRes
public int getCheckedRadioButtonId() {
return mCheckedId;
}
public void clearCheck() {
check(-1);
}
#Override
public GridLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new GridLayout.LayoutParams(getContext(), attrs);
}
#Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof RadioGroup.LayoutParams;
}
#Override
protected GridLayout.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams();
}
#Override
public CharSequence getAccessibilityClassName() {
return RadioGroup.class.getName();
}
public static class LayoutParams extends GridLayout.LayoutParams {
public LayoutParams(Spec rowSpec, Spec columnSpec) {
super(rowSpec, columnSpec);
}
public LayoutParams() {
super();
}
public LayoutParams(ViewGroup.LayoutParams params) {
super(params);
}
public LayoutParams(MarginLayoutParams params) {
super(params);
}
public LayoutParams(GridLayout.LayoutParams source) {
super(source);
}
public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void setBaseAttributes(TypedArray a,
int widthAttr, int heightAttr) {
if (a.hasValue(widthAttr)) {
width = a.getLayoutDimension(widthAttr, "layout_width");
} else {
width = WRAP_CONTENT;
}
if (a.hasValue(heightAttr)) {
height = a.getLayoutDimension(heightAttr, "layout_height");
} else {
height = WRAP_CONTENT;
}
}
}
private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mProtectFromCheckedChange) {
return;
}
mProtectFromCheckedChange = true;
if (mCheckedId != -1) {
setCheckedStateForView(mCheckedId, false);
}
mProtectFromCheckedChange = false;
int id = buttonView.getId();
setCheckedId(id);
}
}
private class PassThroughHierarchyChangeListener implements
ViewGroup.OnHierarchyChangeListener {
private ViewGroup.OnHierarchyChangeListener mOnHierarchyChangeListener;
#Override
public void onChildViewAdded(View parent, View child) {
if (parent == RadioGridLayout.this && child instanceof RadioButton) {
int id = child.getId();
if (id == View.NO_ID) {
id = View.generateViewId();
child.setId(id);
}
((RadioButton) child).setOnCheckedChangeListener(
mChildOnCheckedChangeListener);
}
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewAdded(parent, child);
}
}
#Override
public void onChildViewRemoved(View parent, View child) {
if (parent == RadioGridLayout.this && child instanceof RadioButton) {
((RadioButton) child).setOnCheckedChangeListener(null);
}
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
}
}
}
#Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
structure.setDataIsSensitive(mCheckedId != mInitialCheckedId);
}
}
#Override
public void autofill(AutofillValue value) {
if (!isEnabled()) return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!value.isList()) {
Timber.w(value + " could not be autofilled into " + this);
return;
}
}
int index = 0;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
index = value.getListValue();
}
final View child = getChildAt(index);
if (child == null) {
Timber.w("RadioGroup.autoFill(): no child with index %s", index);
return;
}
check(child.getId());
}
#Override
public int getAutofillType() {
return isEnabled() ? AUTOFILL_TYPE_LIST : AUTOFILL_TYPE_NONE;
}
#Override
public AutofillValue getAutofillValue() {
if (!isEnabled()) return null;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getId() == mCheckedId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return AutofillValue.forList(i);
}
}
}
return null;
}
}
create two radio group.one is for first row and other is for second row.then add the following code in your java code
mFirstGroup = (RadioGroup) findViewById(R.id.first_group);
mSecondGroup = (RadioGroup) findViewById(R.id.second_group);
mFirstGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (checkedId != -1 && isChecking) {
isChecking = false;
mSecondGroup.clearCheck();
mCheckedId = checkedId;
}
isChecking = true;
}
});
mSecondGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (checkedId != -1 && isChecking) {
isChecking = false;
mFirstGroup.clearCheck();
mCheckedId = checkedId;
}
isChecking = true;
}
});
One possible solution is described by #Suhail k k.
Also have a look here (just more details to answer of #Suhail k k.).
I can propose another option:
1) make you own views (ImageView for example) and place them as you wish in your layout; put android:tag on each of them (serial number, for example, from 0 to 7);
2) make selector for each of them (state normal/selected);
3) at runtime put onClickListener on these items like this:
#Override
public void onClick(View v) {
images.get(currentSelected).setSelected(false);
currentSelected = (int) v.getTag();
images.get(currentSelected).setSelected(true);
}
It would be much easier for you to implement, imho.
Hope you got an idea in total, your implementation might be different :)
I am using touch listener for an imageview in the listview item .It is working fine when I just do that like an sample application(I mean I have that Listview item as an sample one). But when I put this in a listview it is really becoming very slow.
I just wants to drag the image only horizantally,for that purpose I used ConstrainedDragandDrop View class which I got from the Github.
In my sample application:
public class HorizontalScroll extends Activity {
ImageView full_left,heart;
RelativeLayout rlMainLayout,rlImages,Cartoon_image,half_left,play_btn,centre,centre_leftanimate;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.inflated_bloops);
half_left=(RelativeLayout)findViewById(R.id.half_left);
Cartoon_image=(RelativeLayout)findViewById(R.id.cartoon_image);
play_btn=(RelativeLayout)findViewById(R.id.play_btn);
heart=(ImageView)findViewById(R.id.ivheart);
ConstrainedDragAndDropView dndView = (ConstrainedDragAndDropView) findViewById(R.id.dndView);
dndView.setDragHandle(findViewById(R.id.cartoon_image),findViewById(R.id.half_left),heart);
dndView.setAllowVerticalDrag(false,HorizontalScroll.this);
}
}
When I used in my Listview:
public class Cars extends BaseAdapter
{
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
LayoutInflater inflator = getLayoutInflater();
v= inflator.inflate(R.layout.inflated_bloops, null);
ConstrainedDragAndDropView dndView = (ConstrainedDragAndDropView) v.findViewById(R.id.dndView);
dndView.setDragHandle(v.findViewById(R.id.cartoon_image),v.findViewById(R.id.half_left),heart);
dndView.setAllowVerticalDrag(false,FeedModeActivity.this);
RelativeLayout Cartoon_image=(RelativeLayout)v.findViewById(R.id.cartoon_image);
ImageView ivDummy =(ImageView)v.findViewById(R.id.dummy);
try{
loader.DisplayImageRelative( al_new.get(position).replace(" ", "%20"),ivDummy, Cartoon_image);
}
catch(Exception e){
e.printStackTrace();
}
return v;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return al_new.size();
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
}
Here is my custom dragDrop view:
public class ConstrainedDragAndDropView extends LinearLayout {
Activity main;
protected View dragHandle,half,heart;
protected List<View> dropTargets = new ArrayList<View>();
protected boolean dragging = false;
protected int pointerId;
protected int selectedDropTargetIndex = -1;
protected int lastSelectedDropTargetIndex = -1;
protected int lastDroppedIndex = -1;
protected boolean allowHorizontalDrag = true;
protected boolean allowVerticalDrag = true;
protected DropListener dropListener;
public interface DropListener {
public void onDrop(final int dropIndex, final View dropTarget);
}
public ConstrainedDragAndDropView(Context context) {
super(context);
}
public ConstrainedDragAndDropView(Context context, AttributeSet attrs) {
super(context, attrs);
applyAttrs(context, attrs);
}
#SuppressLint("NewApi")
public ConstrainedDragAndDropView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
applyAttrs(context, attrs);
}
public DropListener getDropListener() {
return dropListener;
}
public void setDropListener(DropListener dropListener) {
this.dropListener = dropListener;
}
public View getDragHandle() {
return dragHandle;
}
public void setDragHandle(View dragHandle,View half_left,View heart) {
this.dragHandle = dragHandle;
this.half=half_left;
this.heart=heart;
setupDragHandle();
}
public List<View> getDropTargets() {
return dropTargets;
}
public void setDropTargets(List<View> dropTargets) {
this.dropTargets = dropTargets;
}
public void addDropTarget(View target) {
if (dropTargets == null) {
dropTargets = new ArrayList<View>();
}
dropTargets.add(target);
}
public boolean isAllowHorizontalDrag() {
return allowHorizontalDrag;
}
public void setAllowHorizontalDrag(boolean allowHorizontalDrag) {
this.allowHorizontalDrag = allowHorizontalDrag;
}
public boolean isAllowVerticalDrag() {
return allowVerticalDrag;
}
public void setAllowVerticalDrag(boolean allowVerticalDrag,Activity c) {
this.allowVerticalDrag = allowVerticalDrag;
this.main=c;
}
protected void applyAttrs(Context context, AttributeSet attrs) {
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ConstrainedDragAndDropView, 0, 0);
try {
/*
layoutId = a.getResourceId(R.styleable.ConstrainedDragAndDropView_layoutId, 0);
if (layoutId > 0) {
LayoutInflater.from(context).inflate(layoutId, this, true);
}
*/
} finally {
a.recycle();
}
}
protected void setupDragHandle() {
this.setOnTouchListener(new DragAreaTouchListener());
}
protected class DragAreaTouchListener implements OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("Action down", "action down in listener");
onActionDown(view, motionEvent);
break;
case MotionEvent.ACTION_UP:
Log.d("Action up", "action up in listener");
onActionUp(view, motionEvent);
break;
case MotionEvent.ACTION_MOVE:
Log.d("Action move", "action move in listener");
onActionMove(view, motionEvent);
break;
default:
break;
}
return true;
}
}
public static int param;
protected void onActionDown(View view, MotionEvent motionEvent) {
// if we're not already dragging, and the touch position is on the drag handle,
// then start dragging
if(!dragging && isDragHandleTouch(motionEvent)) {
pointerId = motionEvent.getPointerId(0);
Float s1= dragHandle.getX();
param=Integer.valueOf(s1.intValue());
Log.e("param",""+param);
// updateDragPosition(motionEvent);
dragging = true;
Log.d("drag", "drag start");
}
}
protected void onActionUp(View view, MotionEvent motionEvent) {
Log.d("Action up", "action up");
// if we're dragging, then stop dragging
if (dragging && motionEvent.getPointerId(0) == pointerId) {
Log.e("condition","satisfied");
Log.e("x val"+(int)motionEvent.getX(),"y val"+(int)motionEvent.getY());
Log.e("x1"+half.getLeft(),"y1"+half.getTop());
Log.e("x4"+half.getRight(),"y4"+half.getBottom());
Float s1=motionEvent.getX();
Float s2=motionEvent.getY();
int x=Integer.valueOf(s1.intValue());
dragging = false;
int y=Integer.valueOf(s2.intValue());
if((half.getLeft()<x)&&(x<half.getRight())&&((half.getTop()<y)&&(y<half.getBottom())))
{
Log.e("drop","on target");
try {
Thread.sleep(1000);
dragHandle.setX(param);
heart.setVisibility(View.VISIBLE);
Animation pulse = AnimationUtils.loadAnimation(main, R.anim.pulse);
heart.startAnimation(pulse);
// heart.setVisibility(View.GONE);
pulse.setAnimationListener(new AnimationListener() {
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
Log.e("animation","start");
}
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub
Log.e("animation","end");
heart.setVisibility(View.GONE);
}
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// class SimpleThread extends Thread {
//
// public void run() {
//
// try {
// sleep(1000);
// runOnUiThread(new Runnable() {
// public void run() {
// dragHandle.setX(param);
// heart.setVisibility(View.VISIBLE);
//
// Animation pulse = AnimationUtils.loadAnimation(main, R.anim.pulse);
// heart.startAnimation(pulse);
// }
// });
//
// }
// catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
// }
// }
//
// new SimpleThread().start();
}
else{
Log.e("drop",""+"outside target");
dragHandle.setX(param);
// TranslateAnimation transAnimation= new TranslateAnimation(x, 300, y, 300);
// transAnimation.setDuration(1000);//set duration
// view.startAnimation(transAnimation);
}
// if()
// updateDragPosition(motionEvent);
Log.d("drag", "drag end");
// find out what drop target, if any, the drag handle was dropped on
int dropTargetIndex = findDropTargetIndexUnderDragHandle();
if(dropTargetIndex >= 0) { // if drop was on a target, select the target
Log.d("drag", "drop on target " + dropTargetIndex);
// selectDropTarget(dropTargetIndex);
// snapDragHandleToDropTarget(dropTargetIndex);
// lastDroppedIndex = dropTargetIndex;
if(dropListener != null) {
dropListener.onDrop(dropTargetIndex, dropTargets.get(dropTargetIndex));
}
} else { // if drop was not on a target, re-select the last selected target
// deselectDropTarget();
// snapDragHandleToDropTarget(lastDroppedIndex);
}
}
else{
Log.e("condition not","satisfied");
}
}
protected void onActionMove(View view, MotionEvent motionEvent) {
Log.d("Action move", "action move");
if (dragging && motionEvent.getPointerId(0) == pointerId) {
updateDragPosition(motionEvent);
int dropTargetIndex = findDropTargetIndexUnderDragHandle();
if(dropTargetIndex >= 0) {
Log.d("drag", "hover on target " + dropTargetIndex);
// selectDropTarget(dropTargetIndex);
} else {
// deselectDropTarget();
}
}
}
#SuppressLint("NewApi")
protected void updateDragPosition(MotionEvent motionEvent) {
// this is where we constrain the movement of the dragHandle
if(allowHorizontalDrag) {
float candidateX = motionEvent.getX() - dragHandle.getWidth() / 2;
if(candidateX > 0 && candidateX + dragHandle.getWidth() < this.getWidth()) {
dragHandle.setX(candidateX);
}
}
if(allowVerticalDrag) {
float candidateY = motionEvent.getY() - dragHandle.getHeight() / 2;
if(candidateY > 0 && candidateY + dragHandle.getHeight() < this.getHeight()) {
dragHandle.setY(candidateY);
}
}
}
#SuppressLint("NewApi")
protected void snapDragHandleToDropTarget(int dropTargetIndex) {
if(dropTargetIndex > -1) {
View dropTarget = dropTargets.get(dropTargetIndex);
float xCenter = dropTarget.getX() + dropTarget.getWidth() / 2;
float yCenter = dropTarget.getY() + dropTarget.getHeight() / 2;
float xOffset = dragHandle.getWidth() / 2;
float yOffset = dragHandle.getHeight() / 2;
float x = xCenter - xOffset;
float y = yCenter - yOffset;
dragHandle.setX(x);
dragHandle.setY(y);
}
}
protected boolean isDragHandleTouch(MotionEvent motionEvent) {
Point point = new Point(
new Float(motionEvent.getRawX()).intValue(),
new Float(motionEvent.getRawY()).intValue()
);
return isPointInView(point, dragHandle);
}
protected int findDropTargetIndexUnderDragHandle() {
int dropTargetIndex = -1;
for(int i = 0; i < dropTargets.size(); i++) {
if(isCollision(dragHandle, dropTargets.get(i))) {
dropTargetIndex = i;
break;
}
}
return dropTargetIndex;
}
/**
* Determines whether a raw screen coordinate is within the bounds of the specified view
* #param point - Point containing screen coordinates
* #param view - View to test
* #return true if the point is in the view, else false
*/
protected boolean isPointInView(Point point, View view) {
int[] viewPosition = new int[2];
view.getLocationOnScreen(viewPosition);
int left = viewPosition[0];
int right = left + view.getWidth();
int top = viewPosition[1];
int bottom = top + view.getHeight();
return point.x >= left && point.x <= right && point.y >= top && point.y <= bottom;
}
#SuppressLint("NewApi")
protected boolean isCollision(View view1, View view2) {
boolean collision = false;
do {
if(view1.getY() + view1.getHeight() < view2.getY()) {
break;
}
if(view1.getY() > view2.getY() + view2.getHeight()) {
break;
}
if(view1.getX() > view2.getX() + view2.getWidth()) {
break;
}
if(view1.getX() + view1.getWidth() < view2.getX()) {
break;
}
collision = true;
} while(false);
return collision;
}
protected void selectDropTarget(int index) {
if(index > -1) {
deselectDropTarget();
selectedDropTargetIndex = index;
dropTargets.get(selectedDropTargetIndex).setSelected(true);
}
}
protected void deselectDropTarget() {
if(selectedDropTargetIndex > -1) {
dropTargets.get(selectedDropTargetIndex).setSelected(false);
lastSelectedDropTargetIndex = selectedDropTargetIndex;
selectedDropTargetIndex = -1;
}
}
}
I have a Fragment within a FrameLayout. The Fragment contains a VideoView amongst other things. If I modify the FrameLayout's left position (by calling its layout(...) method), the FrameLayout including the Fragment showing within it re-position themselves correctly, all except the VideoView, which sometimes re-positions itself but most often stays put. Anyone know why possibly the VideoView is not re-positioning itself along with its parent, and how I might be able to get it to do so?
Gave up in the end. Doesn't seem to be a straightforward workaround for re-positioning a VideoView, or any workaround for that matter. What I'm doing now instead is to play the video full screen in a new activity.
Try to use this source code for you VideoView.
public class CustomMediaController extends FrameLayout {
/**
* Public interface to handle FullScreenRequest. User can implement this
* interface to make the VideoPlayer Change to FullScreen. The user must
* handle show/hide of views. If the user do not add a Handler the
* FullScreen control button will be hided.
*
* #author Anis
*
*/
public interface FullScreenMediaPlayer {
/**
* Event callback when the MediaPlayer request the FullScreen.
*/
public void onFullScreenRequest();
/**
* Event callback when the MediaPlayer request the go back to normal
* size.
*/
public void onStreatchScreenRequest();
/**
* CallBackEvent when the MediaPlayer is Playing
*/
public void onPlaying();
}
private MediaPlayerControl mPlayer;
private final Context mContext;
private View mAnchor;
private View mRoot;
private View mDecor;
private ProgressBar mProgress;
private TextView mEndTime, mCurrentTime;
private boolean mShowing;
private boolean mDragging;
private static final int sDefaultTimeout = 3000;
private static final int FADE_OUT = 1;
private static final int SHOW_PROGRESS = 2;
private final boolean mUseFastForward;
private boolean mFromXml;
private boolean mListenersSet;
private View.OnClickListener mNextListener, mPrevListener;
StringBuilder mFormatBuilder;
Formatter mFormatter;
private ImageButton mPauseButton;
private ImageButton mFfwdButton;
private ImageButton mRewButton;
private ImageButton mNextButton;
private ImageButton mPrevButton;
// Add Streach colomn
private ImageButton mFullScreenButton;
private boolean isFullSreen;
private FullScreenMediaPlayer fullScreenListener;
public CustomMediaController(Context context, AttributeSet attrs) {
super(context, attrs);
mRoot = this;
mContext = context;
mUseFastForward = true;
mFromXml = true;
isFullSreen = false;
}
#Override
public void onFinishInflate() {
if (mRoot != null)
initControllerView(mRoot);
}
public CustomMediaController(Context context, boolean useFastForward) {
super(context);
mContext = context;
mUseFastForward = useFastForward;
initFloatingWindow();
}
public CustomMediaController(Context context) {
super(context);
mContext = context;
mUseFastForward = true;
initFloatingWindow();
}
private void initFloatingWindow() {
mDecor = this;
mDecor.setOnTouchListener(mTouchListener);
setFocusable(true);
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
requestFocus();
}
private final OnTouchListener mTouchListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mShowing) {
hide();
}
}
return false;
}
};
public void setMediaPlayer(MediaPlayerControl player) {
mPlayer = player;
updatePausePlay();
}
/**
* Set the view that acts as the anchor for the control view. This can for
* example be a VideoView, or your Activity's main view.
*
* #param view
* The view to which to anchor the controller when it is visible.
*/
public void setAnchorView(View view) {
mAnchor = view;
FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT);
removeAllViews();
View v = makeControllerView();
addView(v, frameParams);
}
/**
* Create the view that holds the widgets that control playback. Derived
* classes can override this to create their own.
*
* #return The controller view.
* #hide This doesn't work as advertised
*/
protected View makeControllerView() {
LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRoot = inflate.inflate(R.layout.media_controller, null);
initControllerView(mRoot);
return mRoot;
}
private void initControllerView(View v) {
mPauseButton = (ImageButton) v.findViewById(R.id.pause);
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
}
mFfwdButton = (ImageButton) v.findViewById(R.id.ffwd);
if (mFfwdButton != null) {
mFfwdButton.setOnClickListener(mFfwdListener);
if (!mFromXml) {
mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
}
}
mRewButton = (ImageButton) v.findViewById(R.id.rew);
if (mRewButton != null) {
mRewButton.setOnClickListener(mRewListener);
if (!mFromXml) {
mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
}
}
// By default these are hidden. They will be enabled when
// setPrevNextListeners() is called
mNextButton = (ImageButton) v.findViewById(R.id.next);
if (mNextButton != null && !mFromXml && !mListenersSet) {
mNextButton.setVisibility(View.GONE);
}
mPrevButton = (ImageButton) v.findViewById(R.id.prev);
if (mPrevButton != null && !mFromXml && !mListenersSet) {
mPrevButton.setVisibility(View.GONE);
}
mProgress = (ProgressBar) v.findViewById(R.id.mediacontroller_progress);
if (mProgress != null) {
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mProgress;
seeker.setOnSeekBarChangeListener(mSeekListener);
}
mProgress.setMax(1000);
}
mEndTime = (TextView) v.findViewById(R.id.time);
mCurrentTime = (TextView) v.findViewById(R.id.time_current);
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
mFullScreenButton = (ImageButton) v.findViewById(R.id.video_fullscreen);
installFullScreenListener();
installPrevNextListeners();
}
/**
* Show the controller on screen. It will go away automatically after 3
* seconds of inactivity.
*/
public void show() {
show(sDefaultTimeout);
}
/**
* Show the controller on screen. It will go away automatically after
* 'timeout' milliseconds of inactivity.
*
* #param timeout
* The timeout in milliseconds. Use 0 to show the controller
* until hide() is called.
*/
public void show(int timeout) {
if (!mShowing && mAnchor != null) {
setProgress();
addToFrameAncherLayout();
mShowing = true;
}
updatePausePlay();
// cause the progress bar to be updated even if mShowing
// was already true. This happens, for example, if we're
// paused with the progress bar showing the user hits play.
mHandler.sendEmptyMessage(SHOW_PROGRESS);
Message msg = mHandler.obtainMessage(FADE_OUT);
if (timeout != 0) {
mHandler.removeMessages(FADE_OUT);
mHandler.sendMessageDelayed(msg, timeout);
}
}
private void addToFrameAncherLayout() {
if ((mDecor != null) && (mDecor.getParent() == null)) {
if (mAnchor instanceof FrameLayout) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.BOTTOM;
((FrameLayout) mAnchor).addView(mDecor, params);
mDecor.setVisibility(View.VISIBLE);
} else {
// int[] anchorpos = new int[2];
// mAnchor.getLocationOnScreen(anchorpos);
//
// WindowManager.LayoutParams p = new
// WindowManager.LayoutParams();
// p.gravity = Gravity.TOP;
// p.width = mAnchor.getWidth();
// p.height = LayoutParams.WRAP_CONTENT;
// p.x = anchorpos[0];
// p.y = anchorpos[1] + mAnchor.getHeight() -
// mDecor.getHeight();
// p.format = PixelFormat.TRANSLUCENT;
// p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
// p.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
// p.token = null;
// p.windowAnimations = 0; //
// android.R.style.DropDownAnimationDown;
// mWindowManager.addView(mDecor, p);
// Logger.e("Ancher is not a Frame Layout usinf a Blocking Window");
}
}
mDecor.setVisibility(View.VISIBLE);
}
public boolean isShowing() {
return mShowing;
}
/**
* Remove the controller from the screen.
*/
public void hide() {
if (mAnchor == null)
return;
if (mShowing) {
try {
mHandler.removeMessages(SHOW_PROGRESS);
// TODO must be a New View
if (mDecor != null) {
if (mAnchor instanceof FrameLayout) {
// ((FrameLayout) mAnchor).removeView(mDecor);
mDecor.setVisibility(View.GONE);
} else {
// mWindowManager.removeView(mRoot);
}
}
} catch (IllegalArgumentException ex) {
Log.w("MediaController", "already removed");
}
mShowing = false;
}
}
static class ProgressHandler extends Handler {
WeakReference<CustomMediaController> mediaControllerReference;
ProgressHandler(CustomMediaController mediaController) {
mediaControllerReference = new WeakReference<CustomMediaController>(mediaController);
}
#Override
public void handleMessage(Message msg) {
CustomMediaController mediaController = mediaControllerReference.get();
if (mediaController != null) {
int pos;
switch (msg.what) {
case FADE_OUT:
mediaController.hide();
break;
case SHOW_PROGRESS:
pos = mediaController.setProgress();
if (!mediaController.mDragging && mediaController.mShowing
&& mediaController.mPlayer.isPlaying()) {
msg = obtainMessage(SHOW_PROGRESS);
sendMessageDelayed(msg, 1000 - (pos % 1000));
}
break;
}
}
}
}
private final Handler mHandler = new ProgressHandler(this);
private String stringForTime(int timeMs) {
int totalSeconds = timeMs / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
mFormatBuilder.setLength(0);
if (hours > 0) {
return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
} else {
return mFormatter.format("%02d:%02d", minutes, seconds).toString();
}
}
private int setProgress() {
if (mPlayer == null || mDragging) {
return 0;
}
int position = mPlayer.getCurrentPosition();
int duration = mPlayer.getDuration();
if (mProgress != null) {
if (duration > 0) {
// use long to avoid overflow
long pos = 1000L * position / duration;
mProgress.setProgress((int) pos);
}
int percent = mPlayer.getBufferPercentage();
mProgress.setSecondaryProgress(percent * 10);
}
if (mEndTime != null)
mEndTime.setText(stringForTime(duration));
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime(position));
return position;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
show(sDefaultTimeout);
return true;
}
#Override
public boolean onTrackballEvent(MotionEvent ev) {
show(sDefaultTimeout);
return false;
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
if (event.getRepeatCount() == 0
&& (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
doPauseResume();
show(sDefaultTimeout);
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
if (mPlayer.isPlaying()) {
mPlayer.pause();
updatePausePlay();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
// don't show the controls for volume adjustment
return super.dispatchKeyEvent(event);
} else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
hide();
return true;
} else {
show(sDefaultTimeout);
}
return super.dispatchKeyEvent(event);
}
private final View.OnClickListener mPauseListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
doPauseResume();
show(sDefaultTimeout);
}
};
private void updatePausePlay() {
if (mRoot == null)
return;
ImageButton button = (ImageButton) mRoot.findViewById(R.id.pause);
if (button == null)
return;
if (mPlayer.isPlaying()) {
button.setImageResource(R.drawable.ic_media_pause);
} else {
button.setImageResource(R.drawable.ic_media_play);
}
}
private void doPauseResume() {
if (mPlayer.isPlaying()) {
mPlayer.pause();
} else {
mPlayer.start();
}
updatePausePlay();
}
private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
long duration;
#Override
public void onStartTrackingTouch(SeekBar bar) {
show(3600000);
duration = mPlayer.getDuration();
}
#Override
public void onProgressChanged(SeekBar bar, int progress,
boolean fromtouch) {
if (fromtouch) {
mDragging = true;
duration = mPlayer.getDuration();
long newposition = (duration * progress) / 1000L;
mPlayer.seekTo((int) newposition);
if (mCurrentTime != null)
mCurrentTime
.setText(stringForTime((int) newposition));
} else {
if ((fullScreenListener != null) && (progress > 0)) {
fullScreenListener.onPlaying();
}
}
}
#Override
public void onStopTrackingTouch(SeekBar bar) {
mDragging = false;
setProgress();
updatePausePlay();
show(sDefaultTimeout);
}
};
#Override
public void setEnabled(boolean enabled) {
if (mPauseButton != null) {
mPauseButton.setEnabled(enabled);
}
if (mFfwdButton != null) {
mFfwdButton.setEnabled(enabled);
}
if (mRewButton != null) {
mRewButton.setEnabled(enabled);
}
if (mNextButton != null) {
mNextButton.setEnabled(enabled && mNextListener != null);
}
if (mPrevButton != null) {
mPrevButton.setEnabled(enabled && mPrevListener != null);
}
if (mProgress != null) {
mProgress.setEnabled(enabled);
}
super.setEnabled(enabled);
}
private final View.OnClickListener mRewListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
int pos = mPlayer.getCurrentPosition();
pos -= 5000; // milliseconds
mPlayer.seekTo(pos);
setProgress();
show(sDefaultTimeout);
}
};
private final View.OnClickListener mFfwdListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
int pos = mPlayer.getCurrentPosition();
pos += 15000; // milliseconds
mPlayer.seekTo(pos);
setProgress();
show(sDefaultTimeout);
}
};
private void installPrevNextListeners() {
if (mNextButton != null) {
mNextButton.setOnClickListener(mNextListener);
mNextButton.setEnabled(mNextListener != null);
}
if (mPrevButton != null) {
mPrevButton.setOnClickListener(mPrevListener);
mPrevButton.setEnabled(mPrevListener != null);
}
}
private void installFullScreenListener() {
if (mFullScreenButton != null) {
mFullScreenButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View aView) {
Preconditions.checkNotNull(fullScreenListener,
"IllegalStateExeption, FullScreen Button pressed with a nullable Listener");
if (isFullSreen) {
// send the request to handle normal size;
fullScreenListener.onStreatchScreenRequest();
isFullSreen = false;
updateFullScreenButton();
} else {
// Send request to go FullScreen
fullScreenListener.onFullScreenRequest();
isFullSreen = true;
updateFullScreenButton();
}
}
});
if (fullScreenListener == null) {
mFullScreenButton.setVisibility(View.GONE);
} else {
mFullScreenButton.setVisibility(View.VISIBLE);
}
}
}
/**
* Toggle the Full Screen Buttons
*/
private void updateFullScreenButton() {
if (isFullSreen) {
mFullScreenButton.setImageResource(R.drawable.windowmin);
} else {
mFullScreenButton.setImageResource(R.drawable.windowmax);
}
}
public void setPrevNextListeners(View.OnClickListener next, View.OnClickListener prev) {
mNextListener = next;
mPrevListener = prev;
mListenersSet = true;
if (mRoot != null) {
installPrevNextListeners();
if (mNextButton != null && !mFromXml) {
mNextButton.setVisibility(View.VISIBLE);
}
if (mPrevButton != null && !mFromXml) {
mPrevButton.setVisibility(View.VISIBLE);
}
}
}
public MediaPlayerControl getmPlayer() {
return mPlayer;
}
public void setmPlayer(MediaPlayerControl mPlayer) {
this.mPlayer = mPlayer;
}
#Override
public void dispatchWindowVisibilityChanged(int visibility) {
hide();
}
/**
* #return the fullScreenListener or null if any Listener is registred.
*/
public FullScreenMediaPlayer getFullScreenListener() {
return fullScreenListener;
}
/**
* #param aFullScreenListener
* the fullScreenListener.
*/
public void registerFullScreenListener(FullScreenMediaPlayer aFullScreenListener) {
Preconditions.checkNotNull(aFullScreenListener, "FullScreenListener cannot be null ");
fullScreenListener = aFullScreenListener;
installFullScreenListener();
}
public void removeFullScreenListerer() {
fullScreenListener = null;
installFullScreenListener();
}
/*
* (non-Javadoc)
*
* #see android.view.View#onDetachedFromWindow()
*/
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
hide();
}
}