I am trying to implement a ListPopUpWindow something like the twitter like Menu Popup. But then it's stuck to the right side of the screen. Any help would be appreciated thanks. My code's below
PopUpWindow Method
private void onListPopUp(View anchor) {
ArrayList<Person> persoonItem = new ArrayList<>();
persoonItem.add(new Person(R.drawable.ic_profile_logo, "Oladeji Abubakar", "abubakar.oladeji#deliveryscience.co", ""));
persoonItem.add(new Person(0, "", "", "Update Phone"));
persoonItem.add(new Person(0, "", "", "Your Cards"));
persoonItem.add(new Person(0, "", "", "Invite Friends"));
persoonItem.add(new Person(0, "", "", "Logout"));
ListPopupWindowAdapter mListPopUpWindowAdapter = new ListPopupWindowAdapter(getApplicationContext(), persoonItem);
final ListPopupWindow pop = new ListPopupWindow(this);
pop.setAdapter(mListPopUpWindowAdapter);
pop.setAnchorView(anchor);
pop.setModal(true);
pop.setContentWidth(toolbar.getWidth() / 2);
pop.setHeight(ListPopupWindow.WRAP_CONTENT);
pop.setVerticalOffset(-105);
//pop.setHorizontalOffset(100);
//pop.setPromptPosition(20);
//pop.setHorizontalOffset();
pop.setPromptPosition(0);
pop.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
pop.dismiss();
Toast.makeText(TestActivity.this, "Clicked" + ((Person) parent.getItemAtPosition(position)).getOthers(), Toast.LENGTH_LONG).show();
}
});
pop.show();
WindowManager.LayoutParams wlp = new WindowManager.LayoutParams(toolbar.getWidth()/2, LinearLayout.LayoutParams.WRAP_CONTENT);
wlp.gravity = Gravity.TOP | Gravity.END;
wlp.horizontalMargin = -20;
wlp.x = -20;
View parentView = (View) pop.getListView().getParent();
parentView.setLayoutParams(wlp);
}
And the image
This is what I'm trying to achieve
You can offset the ListPopupWindow by using ListPopupWindow#setHorizontalOffset and ListPopupWindow#setVerticalOffset.
What is confusing is that if your anchor is positioned on the right of the screen you need to add the width value of your ListPopupWindow to the horizontal offset while the vertical offset is always 0 based. Using values below the width for the horizontal offset when the ListPopupWindow is anchored to the right seems to not have any effect. Also positive in the horizontal axis is pointing to the right so we invert the horizontal value.
The following Code positions the ListPopupWindow 5dp down and 5dp to the left from an anchor positioned on the top right:
final ListPopupWindow popupWindow = new ListPopupWindow(context);
int widthPixels = convertDpToPixels(200, context);
int horizontalOffset = -(widthPixels + convertDpToPixels(5, context));
int verticaloffset = convertDpToPixels(5, context);
popupWindow.setAnchorView(anchor);
popupWindow.setWidth(widthPixels);
popupWindow.setHorizontalOffset(horizontalOffset);
popupWindow.setVerticalOffset(verticaloffset);
Related
I have implemented a custom keyboard, that is drawn in an ImageView. Now I want to make it floating, it should be placeable anywhere.
The position, width and height is set in the following way:
private void setKeyboardDimensionAndPosition(int widthPI, int heightPI, int xDP, int yDP) {
WindowManager.LayoutParams windowParams = getWindow().getWindow().getAttributes();
windowParams.x = (int) (xDP * GUIManager.getDensity());
windowParams.y = (int) (yDP * GUIManager.getDensity());
windowParams.width = widthPI;
windowParams.height = heightPI;
(new Handler(Looper.getMainLooper())).post(() -> {
getWindow().getWindow().setAttributes(windowParams);
});
}
But the keyboard is always sticked to the text box - it is always below it! It would even be fine when the text box is covered by the keyboard, it should be totally free!
I want to have a show more button on click of which a popup should be opened with 3 options by default, but as per some logic then options would change ie. hide one of the options based on some condition.
I tried to add a popup menu:
popup = new PopupMenu(this, _showMore, GravityFlags.Top);
popup.MenuInflater.Inflate(Resource.Menu.showMoreMenu, popup.Menu);
if (!string.IsNullOrEmpty(someValue))
{
popup.Menu.FindItem(Resource.Id.ABC1).SetVisible(false);
}
popup.MenuItemClick += Popup_MenuItemClick;
popup.Show();
But in this case, initially, when I have all 3 options the popup is displayed above the button as there is less space below the show more button. But if I hide one of the options then my popup menu opens up at the bottom of the button. I want my popup menu to always be opened above the anchor button.
Then I also tried
PopupWindow popupWindow = new PopupWindow(this); // inflet your layout or diynamic add view
LayoutInflater inflater = (LayoutInflater)GetSystemService(Context.LayoutInflaterService);
View view = inflater.Inflate(Resource.Layout.TestLayout, null, false);
TextView abc1 = (TextView)view.FindViewById(Resource.Id.abc1);
TextView abc2 = (TextView)view.FindViewById(Resource.Id.abc2);
TextView abc3 = (TextView)view.FindViewById(Resource.Id.abc3);
abc1.Click += abc1_Click;
abc2.Click += abc2_Click;
if (!string.IsNullOrEmpty(somecondition))
{
abc1.Visibility = ViewStates.Gone;
}
else
{
abc2.Visibility = ViewStates.Gone;
}
popupWindow.Focusable = (true);
popupWindow.Width = (WindowManagerLayoutParams.WrapContent);
popupWindow.Height = (WindowManagerLayoutParams.WrapContent);
popupWindow.ContentView = (view);
popupWindow.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
/*
//tried
var tttt= (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, Resource.Dimension._15sdp, Resources.DisplayMetrics);
//tried
int test=(int)(Resource.Dimension._15sdp * Resources.DisplayMetrics.Density);
//tried
float scale = Resources.DisplayMetrics.Density;
test= (int)(Resource.Dimension._15sdp * scale + 0.5f);
//tried
var dp = Resource.Dimension._15sdp;
int pixel = (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, dp, Resources.DisplayMetrics);
*/
popupWindow.ShowAsDropDown(_showMore, -220, -570); <-- fixed offset which works for 3 options
The above code works but I have set fixed offset values which I assume will not render it correctly on different resolutions of the phone and also when I hide one of the options from the menu.
I also tried using ListPopupWindow but the same issue of setting the location. Can anybody please help me in setting offsets dynamically.
could it work like this :
int[] location = new int[2];
_showMore.getLocationOnScreen(location);
popupWindow.showAtLocation(_showMore,Gravity.NO_GRAVITY,location[0], location[1] - popupWindow.getHeight());
You can try below code:
fun showPopupAbove(anchor: View) {
viewAnchor = anchor
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
popupWindow.showAsDropDown(anchor)
} else {
popupWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, 0, 0)
}
measureSizeThenUpdatePopupWindowPosition()
}
private fun measureSizeThenUpdatePopupWindowPosition() {
val viewTreeObserver = rootView.viewTreeObserver
if (!viewTreeObserver.isAlive) {
return
}
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
rootView.viewTreeObserver.removeOnGlobalLayoutListener(this)
val anchorRect = getRectFromView(viewAnchor)
// calculate x,y position for display popup window above/below..ect anchor view
var popupWinDownPositionX = (anchorRect.centerX() - rootView.width.toFloat() / 6).toInt()
var popupWinDownPositionY = anchorRect.top
// anchor view close to left
if (popupWinDownPositionX < 0) {
popupWinDownPositionX = 0
}
// anchor view close to top
if (popupWinDownPositionY < 0) {
popupWinDownPositionY = 0
}
// anchor view close to right
if (popupMayExceedsTheScreen(popupWinDownPositionX,
rootView.width)) {
popupWinDownPositionX = (Resources.getSystem().displayMetrics.widthPixels - rootView.width.toFloat()).toInt()
}
popupWindow.update(popupWinDownPositionX, popupWinDownPositionY,
rootView.width, rootView.height)
updateImageArrowMargin(popupWinDownPositionX)
}
})
}
You can modify the value of popupWinDownPositionX and popupWinDownPositionY to fit with your purpose
Thanks, #LeoZhu #LeoZhu's reply. I managed to get it working using the following code
PopupWindow popupWindow = new PopupWindow(this); // inflet your layout or diynamic add view
LayoutInflater inflater = (LayoutInflater)GetSystemService(Context.LayoutInflaterService);
View view = inflater.Inflate(Resource.Layout.TestLayout, null, false);
TextView abc1 = (TextView)view.FindViewById(Resource.Id.abc1);
TextView abc2 = (TextView)view.FindViewById(Resource.Id.abc2);
TextView abc3 = (TextView)view.FindViewById(Resource.Id.abc3);
abc1.Click += GenerateQR_Click;
abc2.Click += PrintQR_Click;
if (!string.IsNullOrEmpty(somecode))
{
abc1.Visibility = ViewStates.Gone;
}
else
{
abc2.Visibility = ViewStates.Gone;
}
int[] location = new int[2];
_showMore.GetLocationOnScreen(location);
popupWindow.Focusable = (true);
popupWindow.Width = (WindowManagerLayoutParams.WrapContent);
popupWindow.Height = (WindowManagerLayoutParams.WrapContent);
popupWindow.ContentView = (view);
popupWindow.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
view.Measure(View.MeasureSpec.MakeMeasureSpec(0, MeasureSpecMode.Unspecified),
View.MeasureSpec.MakeMeasureSpec(0, MeasureSpecMode.Unspecified));
int yOffset = location[1] - (int)(view.MeasuredHeight );
popupWindow.ShowAtLocation(_showMore, GravityFlags.NoGravity, location[0], yOffset);
I need to develop the horizontal split value bar to show the remaining or completed data. There would be 2 horizontal bar - 1 which will have grayed out color and one which will have a filled color by which i need to show some amount of data which user has already used. Please give your input if some of you already have done this.
thanks in advance
private void showBillCycleProgress(int billCycleProgressBarId, int total, int progress, int fillProgressDrawable, int blankProgressDrawable, View view2) {
LinearLayout layout = (LinearLayout) view2.findViewById(billCycleProgressBarId);
layout.removeAllViews();
for (int i = 0; i < total; i++) {
View view = new View(getActivity());
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(35, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(0, 0, 3, 0);
view.setLayoutParams(layoutParams);
view.setBackgroundResource(fillProgressDrawable);
if (i >= progress) {
mHandler.postDelayed(new AnonymousClass(this, view, blankProgressDrawable), (long) (((total - i) * 50) + 200));
}
layout.addView(view);
}
}
I am adding horizontalScrollView programatically , but when I try to do horizontalScrollView.getMeasuredWidth() it keeps returning 0.
void addCategory(String catTitle) {
mVideos = mShows.get(catTitle);
LinearLayout theLayout = (LinearLayout)findViewById(R.id.activitymain);
TextView textview=(TextView)getLayoutInflater().inflate(R.layout.categorytitle,null);
textview.setTextColor(Color.CYAN);
textview.setTextSize(20);
textview.setText(catTitle);
HorizontalScrollView horizontalScroll = new HorizontalScrollView (this,null);
LinearLayout LL = new LinearLayout(this);
LL.setOrientation(LinearLayout.HORIZONTAL);
LayoutParams LLParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
LL.setLayoutParams(LLParams);
HorizontalGalleryAdapter adapter = new HorizontalGalleryAdapter(this,mVideos);
for (int i = 0; i < adapter.getCount(); i++) {
View item = adapter.getView(i, null, null);
LL.addView(item);
}
horizontalScroll.addView(LL);
int maxScrollX = horizontalScroll.getChildAt(0).getMeasuredWidth()-horizontalScroll.getMeasuredWidth();
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("Reset...");
String max= String.valueOf(maxScrollX);
Ok, I see the problem. You create a HorizontalScrollView, add a child to it, and then immediately try to get its measured width.
You cannot do this. You must add the horizontal scroll view to an existing already-drawn view in your activity first, because otherwise it doesn't have set dimensions yet.
Think about how would it know how many pixels WRAP_CONTENT will set the dimension to before its laid out in your view? If you add it to an existing, already-laid-out view in your activity, then that WRAP_CONTENT will actually get converted to some height.
It looks like you kind-of have a loop - horizontalScroll's dimensions depend on its content (WRAP_CONTENT), yet the content's (LinearLayout's) dimensions depend on the horizontalScroll's dimensions. This does not make sense. Perhaps try MATCH_PARENT for at least the width dimensions of your horizontal scroll view. Then, make sure to not look at dimensions until the view has been drawn.
Have a look into typical usage example for HorizontalScrollView:
// read a view's width
private int viewWidth(View view) {
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
return view.getMeasuredWidth();
}
....
void getTableRowHeaderCellWidth(){
int tableAChildCount = ((TableRow)this.tableA.getChildAt(0)).getChildCount();
int tableBChildCount = ((TableRow)this.tableB.getChildAt(0)).getChildCount();;
for(int x=0; x<(tableAChildCount+tableBChildCount); x++){
if(x==0){
this.headerCellsWidth[x] = this.viewWidth(((TableRow)this.tableA.getChildAt(0)).getChildAt(x));
}else{
this.headerCellsWidth[x] = this.viewWidth(((TableRow)this.tableB.getChildAt(0)).getChildAt(x-1));
}
}
}
You can also check full details from this nice tutorial: The code of a Ninja.
I have two views in a RelativeLayout, both of which fill the screen, so view B is on top of view A. I also have an animation defined which can move view B partially offscreen to show view A underneath. The animation works fine, but I'm having the classic issue of the view bounds not moving with the view, so the button that I use to trigger the animation (which is located on view B) is only clickable from its original position, no matter where view B is located. The issue that I'm having is that after the animation ends, when I set the layout params it's causing view B to be redrawn again, translated from the location of the end of the animation.
As a concrete example, the left edge of view B is initially at x = 0, with a button at x = 450. When the button is pressed, an animation moves the view to x = -400. This works properly - the view is partially off the left hand side of the screen, and the button is now at x = 50, so it is still on screen. The click area for the button though is still at x = 450. So now I set the layout params on view B:
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) viewB.getLayoutParams();
lp.rightMargin = 400;
viewB.setLayoutParams(lp);
Once the new params are set, the view gets 400px of padding on the right, moving the entire view to x = -800. The clickable area for the button is now properly at x = 50 though, so it seems like I can have it look right or act right. Any idea what I'm doing wrong? Here's how the animation is set up.
Animation anim = null;
anim = new TranslateAnimation(0, -400, 0, 0);
anim.setAnimationListener(this);
anim.setDuration(duration);
viewB.startAnimation(anim);
I was able to get things working by changing the layout params before or after the animation, as appropriate:
private int marginOffsets;
public void triggerAnimation(boolean show, offset)
{
int curX = 0;
int newX = 0;
Animation anim = null;
this.showingPanel = show;
if(show)
{
curX = 0 - offset;
android.widget.RelativeLayout.LayoutParams lp = new android.widget.RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
lp.rightMargin = 0;
rootPanel.setLayoutParams(lp);
}
else
{
newX = 0 - offset;
}
marginOffsets = newX < 0 ? 0 - offset : offset;
anim = new TranslateAnimation(curX, newX, 0, 0);
anim.setAnimationListener(this);
anim.setDuration(duration);
startAnimation(anim);
}
public void onAnimationEnd(Animation anim)
{
//This prevents flicker when the view is moving onscreen.
clearAnimation();
if(!showingPanel)
{
//Move the margin to move the actual bounds so click events still work.
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
lp.rightMargin = 0 - marginOffsets;
rootPanel.setLayoutParams(lp);
}
}