仿QQ空間根據位置彈出PopupWindow顯示更多操作效果

来源:http://www.cnblogs.com/teamblog/archive/2016/12/08/6145768.html
-Advertisement-
Play Games

我們打開QQ空間的時候有個箭頭按鈕點擊之後彈出PopupWindow會根據位置的變化顯示在箭頭的上方還是下方,比普通的PopupWindow彈在屏幕中間顯示好看的多。 先看QQ空間效果圖: 這個要實現這個效果可以分幾步進行 1.第一步自定義PopupWindow,實現如圖的樣式,這個繼承PopupW ...


我們打開QQ空間的時候有個箭頭按鈕點擊之後彈出PopupWindow會根據位置的變化顯示在箭頭的上方還是下方,比普通的PopupWindow彈在屏幕中間顯示好看的多。

先看QQ空間效果圖:

                           

這個要實現這個效果可以分幾步進行

1.第一步自定義PopupWindow,實現如圖的樣式,這個繼承PopupWindow自定義佈局很容易實現

2.得到點擊按鈕的位置,根據位置是否在屏幕的中間的上方還是下方,將PopupWindow顯示在控制項的上方或者下方

3.適配問題,因為PopupWindow上面的操作列表是動態的所以要自定義listView

4.動畫效果+背景變暗

通過步驟分析,我們就很清晰的瞭解我們要做什麼,話不多說,從第一步開始吧

下麵自定義PopupWindow實現效果

1.重寫listView,重新計算高度(一般也應用於解決ScrollView嵌套listView只顯示一行的問題)

public class MyListView extends ListView {
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public MyListView(Context context) {
super(context);
}

public MyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST));
}
}

2.自定義PopupWindow的佈局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="right">
<ImageView
android:id="@+id/arrow_up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="28dp"
android:src="@drawable/arrow_up_white"
android:visibility="visible"/>
<com.widget.MyListView
android:id="@+id/lv_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/normal_margin8"
android:layout_marginTop="-1dp"
android:layout_marginBottom="-1dp"
android:dividerHeight="0dp"
android:layout_marginLeft="@dimen/normal_margin8"
android:layout_marginRight="@dimen/normal_margin8"
android:scrollbars="none"
android:background="@drawable/custom_white"
android:divider="@null"></com.widget.MyListView>
<ImageView
android:id="@+id/arrow_down"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="28dp"
android:src="@drawable/arrow_down_white"
android:visibility="visible"/>
</LinearLayout>

2.PopupWindow彈出動畫以及消失動畫

popshow_operation_anim_down.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="0.0"
android:toXScale="1.0"
android:fromYScale="0.0"
android:toYScale="1.0"
android:pivotX="90%"
android:pivotY="0%"
android:fillAfter="false"
android:duration="300" >
</scale>
</set>
popshow_operation_anim_up.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="0.0"
android:toXScale="1.0"
android:fromYScale="0.0"
android:toYScale="1.0"
android:pivotX="90%"
android:pivotY="100%"
android:fillAfter="false"
android:duration="250" >
</scale>
</set>

 消失動畫是漸隱動畫可以自己定義,同理。

3.重寫PopupWindow了

public class CustomOperationPopWindow extends PopupWindow {
private Context context;
private View conentView;
private View backgroundView;
private Animation anim_backgroundView;
private MyListView listView;
private TypeSelectPopuAdapter selectAdapter;
ImageView arrow_up, arrow_down;
List<TypeSelect> typeSelectlist = new ArrayList<>();
int[] location = new int[2];
private OnItemListener onItemListener;
private AdapterView.OnItemClickListener onItemClickListener;

public interface OnItemListener {
public void OnItemListener(int position, TypeSelect typeSelect);
}

;

public void setOnItemMyListener(OnItemListener onItemListener) {
this.onItemListener = onItemListener;
}

public CustomOperationPopWindow(Context context) {
this.context = context;
initView();
}

public CustomOperationPopWindow(Context context, List<TypeSelect> typeSelectlist) {
this.context = context;
this.typeSelectlist = typeSelectlist;
initView();
}

private void initView() {
this.anim_backgroundView = AnimationUtils.loadAnimation(context, R.anim.alpha_show_anim);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.conentView = inflater.inflate(R.layout.view_operation_popupwindow, null);
// 設置SelectPicPopupWindow的View
this.setContentView(conentView);
// 設置SelectPicPopupWindow彈出窗體的寬
this.setWidth(LayoutParams.MATCH_PARENT);
// 設置SelectPicPopupWindow彈出窗體的高
this.setHeight(LayoutParams.WRAP_CONTENT);
// 設置SelectPicPopupWindow彈出窗體可點擊
this.setFocusable(true);
this.setOutsideTouchable(true);
// 刷新狀態
this.update();
// 實例化一個ColorDrawable顏色為半透明
ColorDrawable dw = new ColorDrawable(0000000000);
// 點back鍵和其他地方使其消失,設置了這個才能觸發OnDismisslistener ,設置其他控制項變化等操作
this.setBackgroundDrawable(dw);
// 設置SelectPicPopupWindow彈出窗體動畫效果
this.setAnimationStyle(R.style.operation_popwindow_anim_style_up);
this.listView = (MyListView) conentView.findViewById(R.id.lv_list);
this.arrow_up = (ImageView) conentView.findViewById(R.id.arrow_up);
this.arrow_down = (ImageView) conentView.findViewById(R.id.arrow_down);

//設置適配器
this.selectAdapter = new TypeSelectPopuAdapter(context, typeSelectlist,
R.layout.item_operation_popu);
this.listView.setAdapter(selectAdapter);
this.listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (isShowing()) {
dismiss();
}
onItemListener.OnItemListener(position, typeSelectlist.get(position));
}
});
this.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss() {
if (backgroundView != null) {
backgroundView.setVisibility(View.GONE);
}
}
});
}

//設置數據
public void setDataSource(List<TypeSelect> typeSelectlist) {
this.typeSelectlist = typeSelectlist;
this.selectAdapter.notifyDataSetChanged();
}


/**
* 沒有半透明背景 顯示popupWindow
*
* @param
*/
public void showPopupWindow(View v) {
v.getLocationOnScreen(location); //獲取控制項的位置坐標
//獲取自身的長寬高
conentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
if (location[1] > MainApplication.SCREEN_H / 2 + 100) { //MainApplication.SCREEN_H 為屏幕的高度,方法可以自己寫
this.setAnimationStyle(R.style.operation_popwindow_anim_style_up);
arrow_up.setVisibility(View.GONE);
arrow_down.setVisibility(View.VISIBLE);
this.showAtLocation(v, Gravity.NO_GRAVITY, (location[0]), location[1] - conentView.getMeasuredHeight());
} else {
this.setAnimationStyle(R.style.operation_popwindow_anim_style_down);
arrow_up.setVisibility(View.VISIBLE);
arrow_down.setVisibility(View.GONE);
this.showAsDropDown(v, 0, 0);
}
}

/**
* 攜帶半透明背景 顯示popupWindow
*
* @param
*/
public void showPopupWindow(View v, View backgroundView) {
this.backgroundView = backgroundView;
v.getLocationOnScreen(location); //獲取控制項的位置坐標
//獲取自身的長寬高
conentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
backgroundView.setVisibility(View.VISIBLE);
//對view執行動畫
backgroundView.startAnimation(anim_backgroundView);
if (location[1] > MainApplication.SCREEN_H / 2 + 100) { //若是控制項的y軸位置大於屏幕高度的一半,向上彈出
this.setAnimationStyle(R.style.operation_popwindow_anim_style_up);
arrow_up.setVisibility(View.GONE);
arrow_down.setVisibility(View.VISIBLE);
this.showAtLocation(v, Gravity.NO_GRAVITY, (location[0]), location[1] - conentView.getMeasuredHeight()); //顯示指定控制項的上方
} else {
this.setAnimationStyle(R.style.operation_popwindow_anim_style_down); //反之向下彈出
arrow_up.setVisibility(View.VISIBLE);
arrow_down.setVisibility(View.GONE);
this.showAsDropDown(v, 0, 0); //顯示指定控制項的下方
}
}
/**
* 顯示popupWindow 根據特殊要求高度顯示位置
*
* @param
*/
public void showPopupWindow(View v, View backgroundView,int hight) {
this.backgroundView = backgroundView;
v.getLocationOnScreen(location);
//獲取自身的長寬高
conentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
backgroundView.setVisibility(View.VISIBLE);
//對view執行動畫
backgroundView.startAnimation(anim_backgroundView);
if (location[1] > MainApplication.SCREEN_H / 2 + 100) {
this.setAnimationStyle(R.style.operation_popwindow_anim_style_up);
arrow_up.setVisibility(View.GONE);
arrow_down.setVisibility(View.VISIBLE);
this.showAtLocation(v, Gravity.NO_GRAVITY, (location[0]), location[1] - conentView.getMeasuredHeight()-hight);
} else {
this.setAnimationStyle(R.style.operation_popwindow_anim_style_down);
arrow_up.setVisibility(View.VISIBLE);
arrow_down.setVisibility(View.GONE);
this.showAsDropDown(v, 0, 0);
}
}
}

 4.代碼中的用法

    1.

CustomOperationPopWindow  customOperationPopWindow = new CustomOperationPopWindow(this, operationTypeSelectlist);
customOperationPopWindow.setOnItemMyListener(new CustomOperationPopWindow.OnItemListener() {
@Override
public void OnItemListener(int position, TypeSelect typeSelect) {
//此處實現列表點擊所要進行的操作
}
});

   2.

textView.setOnClickListener(new View.OnClickListener() {
    @Override
public void onClick(View v) {
customOperationPopWindow.showPopupWindow(textView);//可以傳個半透明view v_background過去根據業務需要顯示隱藏
    }
});

 5.最終實際效果

                        

             

以上代碼為幾乎主要全部代碼,主要是PopupWindow的用法,思路清晰一步一步實現很簡單。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最為一個剛入職不久的小白。。。慢慢磨練吧。。。 JS實現頁面返回定位到具體位置 其實瀏覽器也自帶了返回的功能,也就是說,自帶了返回定位的功能。正常的跳轉,返回確實可以定位,但是有些特殊場景就不適用了。例如,某些元素是在某種情況下才加上的,又或者多級定位。 目前,我知道的返回定位到具體位置有兩種方法: ...
  • 一個簡單的js計時函數(多次定時) ...
  • 這幾篇都是我原來首發在 segmentfault 上的地址:https://segmentfault.com/a/1190000004996659 突然想起來我這個博客冷落了好多年了,也該更新一下,呵呵 最近想重寫一下網站的Restful API,原來是用PHP寫的,看到現在nodejs這麼火也想試 ...
  • × 目錄 [1]URI [2]URL語法 [3]字元[4]編碼方法 前面的話 一般地,URL和URI比較難以區分。接下來,本文以區分URL和URI為引子,詳細介紹URL的用法 URI與URL的區別 URI是Uniform Resource Identifier的縮寫,稱為統一資源標識符。URI是一個 ...
  • 方法一:(jQuery方法: 適用所有瀏覽器) HTML頁面: 方法二:(AJAX XMLHTTP方法: 使用ActiveXObject,所以僅支持IE,非IE內核瀏覽器不可用。) <script type="text/javascript"> function chkurl(url) { var  ...
  • 嘿嘿 我也是查網上的啦 然後放到我的博客里來 下次就會了 ...
  • 一個好的app不光要用好的功能,還要有好的界面,這樣內外兼修才算得上是一個好的App。其實跟人一樣,不能只刷帥,要有內涵(看清楚哦,內涵不是指悶騷)。 ...
  • 我們在使用APP的過程中,軟體會偶爾提示我們進行版本更新,我們點擊確認更新後,會在通知欄顯示下載更新進度(已知長度的進度條)以及安裝情況(不確定進度條),這就是我們今天要實現的功能。實現效果如下: 在代碼實現功能前,我們先解釋進度條的兩種狀態: (1)顯示一個已知長度的進度條指示器(Displayi ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...