PopUpWindow 有两个常用接口:
一、public void showAsDropDown(View anchor, int xoff, int yoff)
showAsDropDown(View anchor, int xoff, int yoff)这个API见名思意就是PopupWindow显示在anchor周围。默认的坐标原点是anchor的左下角。
off/yoff的坐标系也是以anchor这个View的左下角为坐标原点。
xoff为正PopupWindow就会向右偏;yoff为正PopupWindow就向下偏。
/**
* Display the content view in a popup window anchored to the bottom-left
* corner of the anchor view. If there is not enough room on screen to show
* the popup in its entirety, this method tries to find a parent scroll
* view to scroll. If no parent scroll view can be scrolled, the
* bottom-left corner of the popup is pinned at the top left corner of the
* anchor view.
*
* @param anchor the view on which to pin the popup window
*
* @see #dismiss()
*/
public void showAsDropDown(View anchor)
/**
* Display the content view in a popup window anchored to the bottom-left
* corner of the anchor view offset by the specified x and y coordinates.
* If there is not enough room on screen to show the popup in its entirety,
* this method tries to find a parent scroll view to scroll. If no parent
* scroll view can be scrolled, the bottom-left corner of the popup is
* pinned at the top left corner of the anchor view.
* <p>
* If the view later scrolls to move <code>anchor</code> to a different
* location, the popup will be moved correspondingly.
*
* @param anchor the view on which to pin the popup window
* @param xoff A horizontal offset from the anchor in pixels
* @param yoff A vertical offset from the anchor in pixels
*
* @see #dismiss()
*/
public void showAsDropDown(View anchor, int xoff, int yoff)
二、 public void showAtLocation(View parent, int gravity, int x, int y)
showAtLocation() 可以让PopUpWindow显示在DecorView的任意地方,参数x和y的坐标也是相对于整个Screen来说的。
/**
* <p>
* Display the content view in a popup window at the specified location. If the popup window
* cannot fit on screen, it will be clipped. See {@link android.view.WindowManager.LayoutParams}
* for more information on how gravity and the x and y parameters are related. Specifying
* a gravity of {@link android.view.Gravity#NO_GRAVITY} is similar to specifying
* <code>Gravity.LEFT | Gravity.TOP</code>.
* </p>
*
* @param parent a parent view to get the {@link android.view.View#getWindowToken()} token from
* @param gravity the gravity which controls the placement of the popup window
* @param x the popup's x location offset
* @param y the popup's y location offset
*/
public void showAtLocation(View parent, int gravity, int x, int y)
1、第一个参数parent,popUpWindow从parent获取WindowToken,该参数不影响popupWindow的位置。
a parent view to get the {@link android.view.View#getWindowToken()} token from
2、第二个参数gravity就是设置屏幕坐标原点。
Gravity.LEFT | Gravity.TOP就是以屏幕左上角为坐标原点。
3、第三个参数x就是在屏幕坐标系上的x坐标,第四个参数就是y坐标了。
- 以屏幕的左上角为坐标原点。popUpWindwo的左上角定位到(100,200)的位置。
或者可以理解为将屏幕的左上角为坐标原点,首先将popupWindow 的左上角放置到屏幕左上角,然后将popupWindow向右移动100,向下移动200
gravity = Gravity.LEFT | Gravity.TOP
x = 100
y = 200
- 以屏幕的右上角为坐标原点。popUpWindwo的右上角定位到(100,200)的位置。
或者可以理解为将屏幕的右上角为坐标原点,首先将popupWindow 的右上角放置到屏幕的右上角,然后将popupWindow向左移动100,向下移动200
gravity = Gravity.RIGHT | Gravity.TOP
x = 100
y = 200
- 以屏幕的左下角为坐标原点。popUpWindwo的左下角定位到(100,200)的位置。
或者可以理解为将屏幕的左下角为坐标原点,首先将popupWindow 的左下角放置到屏幕的左下角,然后将popupWindow向右移动100,向上移动200
gravity = Gravity.LEFT | Gravity.BOTTOM
x = 100
y = 200
- 以屏幕的右下角为坐标原点。popUpWindwo的右下角定位到(100,200)的位置。
或者可以理解为将屏幕的右下角为坐标原点,首先将popupWindow 的右下角放置到屏幕的右下角,然后将popupWindow向左移动100,向上移动200
gravity = Gravity.RIGHT | Gravity.BOTTOM
x = 100
y = 200
三、利用popUpWindow 模仿IOS 的长按弹出选择框控件,选项超出屏幕宽度后,支持分屏显示。
public class PopSelectWindow extends PopupWindow {
public static final String TAG =PopSelectWindow.class.getSimpleName();
private PopSelectWindow(Context context){
super(context);
mContext = context;
}
public PopSelectWindow(Builder builder){
super(builder.mContext);
mContext = builder.mContext;
mSelectOptions.clear();
mSelectOptions.addAll(builder.mSelectOptions);
mListeners.clear();
mListeners.putAll(builder.mListeners);
mTextSize = builder.mTextSize;
mPopUpViewWidth = builder.mPopUpViewWidth;
mPopUpViewHeight = builder.mPopUpViewHeight;
mOption_margin = builder.mOption_margin;
mPopUpViewMarginTop = builder.mPopUpViewMarginTop;
mPopUpviewMarginBottom = builder.mPopUpviewMarginBottom;
}
public static final int DefaultTextSize = 18;
public static final int DefaultPopUpViewWidth = 470;
public static final int DefaultPopUpViewHeight = 62;
public static final int DefaultPopUpViewMarginTop = 5;
public static final int DefaultPopUpViewMarginBottom = 5;
public static final int DefaultOptionMargin = 10;
private Context mContext;
private int mTextSize = DefaultTextSize;//选项文本字体大小sp
private int mPopUpViewWidth = DefaultPopUpViewWidth;// 470
private int mPopUpViewHeight = DefaultPopUpViewHeight;//popUpWindow 的高度,单位px
private int mPopUpViewMarginTop = DefaultPopUpViewMarginTop;//popUpView 距离AnchorView的距离
private int mPopUpviewMarginBottom = DefaultPopUpViewMarginBottom;
private int mOption_margin = DefaultOptionMargin;//px //选项之前的间隔,单位px
private List<String>mSelectOptions = new ArrayList<>();
private Map<String,PopSelectionListener> mListeners = new HashMap();
private Map<Integer,List<TheOption>> mPageData = new HashMap<>();// Integer 代表页面的编号,List<TheOption> 代表该页面对应的选项集合(包括左箭头和右箭头)
private int mTotalPage = 0;//总分页数
public int mCurrentPage = 0;//当前的页码
public void putPageData(Integer page,TheOption theOption){
List<TheOption> theOptionList = mPageData.get(page);
if(theOptionList == null){
theOptionList = new ArrayList<>();
}
theOptionList.add(theOption);
mPageData.put(page,theOptionList);
}
public void addLeftArrow(List<TheOption>theOptions){
if(theOptions != null){
theOptions.add(0,TheOption.createLeftArrow());
}
}
public void addRightArrow(List<TheOption>theOptions){
if(theOptions != null){
theOptions.add(TheOption.createRightArrow());
}
}
public int calculateSingleOptionWidth(String optionStr){
TextView textView = new TextView(mContext);
textView.setTextSize(mTextSize);
TextPaint textPaint = textView.getPaint();
float width = textPaint.measureText(optionStr);
int finalWidth = (int)width+ mOption_margin*2;
LogUtil.d(TAG,"calculateTotalNeedWidth:"+width+",option:"+optionStr);
return finalWidth;
}
public void calculate(){
int totalNeedWidth = 0;
int totalPages = 0;
for(int i = 0;i< mSelectOptions.size();i++){
String optionStr = mSelectOptions.get(i);
TheOption theOption = new TheOption();
theOption.mOptionName = optionStr;
theOption.needWidth = calculateSingleOptionWidth(optionStr);
theOption.mListener = mListeners.get(optionStr);
totalNeedWidth+=theOption.needWidth;
boolean isPageFull = totalNeedWidth> mPopUpViewWidth;
if(isPageFull){
totalPages++;
totalNeedWidth= theOption.needWidth;
}
theOption.page = totalPages;
putPageData(totalPages,theOption);
}
LogUtil.d(TAG,"calculate:"+totalPages);
mTotalPage = totalPages;
for(int i = 0 ;i <= mTotalPage;i++){
if(mTotalPage > 0 ){ //数据多于一页
if(i == 0 ){ //针对第一页:如果数据多于一页,则为第一页 尾部增加一个右向箭头
addRightArrow(mPageData.get(i));
}else if(i == mTotalPage){//针对最后一页:如果数据多余一页,则为最后一页头部,怎家一个左向箭头
addLeftArrow(mPageData.get(i));
}else {//针对中间的选项:如果数据多余一页,则为该页数据 增加左向箭头和右向箭头
addLeftArrow(mPageData.get(i));
addRightArrow(mPageData.get(i));
}
}else {//数据只有一页,则不用添加左向箭头和右向箭头
//do nothing
}
}
// printData();
}
public void printData(){
for(Integer index:mPageData.keySet()){
LogUtil.d(TAG,"feifei page---------------:"+index);
List<TheOption> options = mPageData.get(index);
if(options == null){
return;
}
for(int i = 0 ;i< options.size();i++){
LogUtil.d(TAG,"feifei page- selection:"+options.get(i).mOptionName+",needWidth:"+options.get(i).needWidth);
}
}
}
LinearLayout ll_content;
ImageView iv_top_arrow;
ImageView iv_bottom_arrow;
public void show_AtLocation(View anchorView,int leftX,int topY,int screenCenterY){
View container = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.layout_pop_selection, null);
ll_content = (LinearLayout) container.findViewById(R.id.ll_content);
iv_top_arrow = (ImageView)container.findViewById(R.id.iv_top_arrow);
iv_bottom_arrow = (ImageView)container.findViewById(R.id.iv_bottom_arrow);
DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
int screenHeigth = SystemFacade.getScreenHeight(anchorView.getContext());
int screenWidth = SystemFacade.getScreenWidth(anchorView.getContext());
int anchorViewHeidht = anchorView.getHeight();
int anchorViewWidth = anchorView.getWidth();
boolean needShowUp = false;
if(topY+anchorViewHeidht+ mPopUpViewHeight >screenHeigth){
needShowUp = true;
}
int moveX = 0;
int moveY = 0;
int centerY_Up = (topY - mPopUpViewHeight -mPopUpViewMarginTop);
int centerY_Down = (topY + anchorViewHeidht+mPopUpviewMarginBottom);
//centerY_Up和centerY_Down 哪个距离屏幕中心位置较近,则以哪个为准,进行显示。
if(screenCenterY-centerY_Up < centerY_Down-screenCenterY){
needShowUp = true;
}else {
needShowUp = false;
}
if(needShowUp){ //需要在上放显示
iv_top_arrow.setVisibility(View.GONE);
iv_bottom_arrow.setVisibility(View.VISIBLE);
moveX = (screenWidth- mPopUpViewWidth)/2;
moveY = (topY - mPopUpViewHeight -mPopUpViewMarginTop);
}else {
iv_bottom_arrow.setVisibility(View.GONE);
iv_top_arrow.setVisibility(View.VISIBLE);
moveX = (screenWidth- mPopUpViewWidth)/2;
moveY = (topY + anchorViewHeidht+mPopUpviewMarginBottom);
}
moveX = mPopUpViewWidth;
moveY = mPopUpViewHeight;
calculate();
updateView();
this.setContentView(container);
this.setBackgroundDrawable(new ColorDrawable(0x00000000));
this.setOutsideTouchable(false);
this.setWidth(mPopUpViewWidth);
this.setFocusable(true);
//以屏幕左上角未原点,向左和向下移动(moveX, moveY)个距离
// this.showAtLocation(anchorView, Gravity.TOP|Gravity.LEFT, moveX, moveY);
this.showAsDropDown(anchorView,moveX,moveY);
}
public void updateView(){
ll_content.removeAllViews();
if(mCurrentPage < mPageData.size()) {
List<TheOption> thePageDatas = mPageData.get(mCurrentPage);
if (thePageDatas != null) {
for (int index = 0; index < thePageDatas.size(); index++) {
TheOption theOption = thePageDatas.get(index);
if (theOption.type == TYPE_LEFT_ARROW) {
createArrow(theOption.type);
} else if (theOption.type == TYPE_OPTION) {
createText(theOption);
boolean shouldCreateLine = false;
if(index == thePageDatas.size() -1 ){ //最后一列 不显示竖线
shouldCreateLine = false;
}else {
if(thePageDatas.size() > 2 && index == thePageDatas.size()-2 //是 某一页中 倒数第二项,切最后一项是箭头,则不显示横线
&& thePageDatas.get(index+1).type == TYPE_RIGHT_ARROW){
shouldCreateLine = false;
}else{
shouldCreateLine = true;
}
}
if(shouldCreateLine){
createLine();
}
} else if (theOption.type == TYPE_RIGHT_ARROW) {
createArrow(theOption.type);
}
}
}
}
}
public TextView createLine(){
TextView line = new TextView(mContext);
LinearLayout.LayoutParams lineParams = new LinearLayout.LayoutParams(1, 40);
lineParams.gravity = Gravity.CENTER_VERTICAL;
line.setLayoutParams(lineParams);
line.setBackgroundColor(mContext.getColor(R.color.color_252525));
ll_content.addView(line);
return line;
}
public ImageView createArrow(int type){
ImageView imageView = new ImageView(mContext);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT);
layoutParams.gravity = Gravity.CENTER_VERTICAL;
imageView.setLayoutParams(layoutParams);
imageView.setPadding(5,0,5,0);
if(type == TYPE_LEFT_ARROW){
imageView.setImageResource(R.drawable.selctor_selection_left_arrow);
}else {
imageView.setImageResource(R.drawable.selector_selection_right_arrow);
}
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(type == TYPE_LEFT_ARROW){
go2prevPage();
}else {
go2nextPage();
}
}
});
ll_content.addView(imageView);
return imageView;
}
public void createText(final TheOption theOption){
TextView textView = new TextView(mContext);
textView.setTextSize(mTextSize);
textView.setText(theOption.mOptionName);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT);
layoutParams.weight = 1.0f;
textView.setLayoutParams(layoutParams);
textView.setGravity(Gravity.CENTER);
textView.setTextColor(mContext.getColor(R.color.color_dddddd));
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PopSelectWindow.this.dismiss();
if(theOption.mListener!=null){
theOption.mListener.clicked(theOption.mOptionName);
}
}
});
textView.setBackgroundColor(mContext.getColor(R.color.color_3a3a3a));
ll_content.addView(textView);
}
public void go2nextPage(){
mCurrentPage++;
if(mCurrentPage >= mTotalPage){
mCurrentPage = mTotalPage;
}
updateView();
LogUtil.d(TAG,"go2nextPage:"+mCurrentPage+",totalPage:"+mTotalPage);
}
public void go2prevPage(){
mCurrentPage--;
if(mCurrentPage <= 0){
mCurrentPage = 0;
}
updateView();
LogUtil.d(TAG,"go2prevPage:"+mCurrentPage+",totalPage:"+mTotalPage);
}
public static class TheOption{
String mOptionName = "";
int needWidth = 0;
int type = TYPE_OPTION;
int page;
PopSelectionListener mListener;
public static TheOption createLeftArrow(){
TheOption theOption = new TheOption();
theOption.type = TYPE_LEFT_ARROW;
theOption.mOptionName="<-";
return theOption;
}
public static TheOption createRightArrow(){
TheOption theOption = new TheOption();
theOption.type = TYPE_RIGHT_ARROW;
theOption.mOptionName="->";
return theOption;
}
}
public static final int TYPE_LEFT_ARROW = 0;
public static final int TYPE_OPTION = 1;
public static final int TYPE_RIGHT_ARROW = 2;
public static class Builder{
private Context mContext;
private List<String>mSelectOptions = new ArrayList<>();
private Map<String,PopSelectionListener> mListeners = new HashMap();
private int mTextSize = 18;//选项文本字体大小sp
private int mPopUpViewWidth = 200;
private int mOption_margin = 10;//
private int mPopUpViewHeight = 62;//popUpWindow 的高度,单位px
private int mPopUpViewMarginTop = 5;//popUpView 距离AnchorView的距离
private int mPopUpviewMarginBottom = 5;
public Builder(Context context){
mContext = context;
}
public Builder setTextSize(int textSize){
mTextSize = textSize;
return this;
}
public Builder setPopUpViewWidth(int width){
mPopUpViewWidth = width;
return this;
}
public Builder setOptionMargin(int option_margin){
mOption_margin = option_margin;
return this;
}
public Builder setPopUpViewHeight(int height){
mPopUpViewHeight = height;
return this;
}
public Builder setPopUpViewMarginTop(int margin_top){
this.mPopUpViewMarginTop = margin_top;
return this;
}
public Builder setPopUpViewMarginBottom(int margin_bottom){
this.mPopUpviewMarginBottom = margin_bottom;
return this;
}
public Builder addItem(String selection,PopSelectionListener listener){
mSelectOptions.add(selection);
mListeners.put(selection,listener);
return this;
}
public PopSelectWindow build(){
PopSelectWindow popSelectWindow = new PopSelectWindow(this);
return popSelectWindow;
}
}
public interface PopSelectionListener{
public void clicked(String msg);
}
调用方法:
int navigationHeight = 80; //导航栏高度
int scrreenHeight = SystemFacade.getScreenHeight(this);
int screenCenterY = (scrreenHeight-navigationHeight)/2;
popupWindow = new PopSelectWindow.Builder(this)
.setTextSize(18)
.setPopUpViewWidth(200)
.setPopUpViewHeight(62)
.setPopUpViewMarginBottom(5)
.setPopUpViewMarginTop(5)
.setOptionMargin(10)
.addItem(getString(R.string.full_show), new PopSelectWindow.PopSelectionListener() {
@Override
public void clicked(String msg) {
go2BigView(item);
LogUtil.d(TAG,"clicked:"+msg);
}
}).addItem(getString(R.string.text_favorite), new PopSelectWindow.PopSelectionListener() {
@Override
public void clicked(String msg) {
doSinglefavoirteAction(item);
LogUtil.d(TAG,"clicked:"+msg);
}
})
.addItem(getString(R.string.text_multi_select), new PopSelectWindow.PopSelectionListener() {
@Override
public void clicked(String msg) {
setMultiSelectMode(true);
LogUtil.d(TAG,"clicked:"+msg);
}
}).addItem(getString(R.string.delete), new PopSelectWindow.PopSelectionListener() {
@Override
public void clicked(String msg) {
showDeleteDialog(item);
LogUtil.d(TAG,"clicked:"+msg);
}
}).addItem(getString(R.string.feedback), new PopSelectWindow.PopSelectionListener() {
@Override
public void clicked(String msg) {
g2oTranslateFeedBack(item);
LogUtil.d(TAG,"clicked:"+msg);
}
})
.build();
popupWindow.show_AtLocation(anchorView,leftX,topY,screenCenterY);
网友评论