Android 天气APP(八)城市切换 之 自定义弹窗与使用(上)

简介: Android 天气APP(八)城市切换 之 自定义弹窗与使用(上)

自定义弹窗


既然是弹窗,那就不能让它平白无奇的出现,给一个动画效果,闪亮登场,完美谢幕。


20200404231219294.png


in_bottom_to_top.xml


<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromYDelta="100%p"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:toYDelta="0%p" >
</translate>


in_right_to_left.xml


<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromXDelta="100%p"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:toXDelta="0%p" >
</translate>


out_left_to_right.xml


<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromXDelta="0%p"
    android:toXDelta="100%p"
    android:interpolator="@android:anim/accelerate_interpolator" >
</translate>


out_top_to_bottom.xml


<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromYDelta="0%p"
    android:toYDelta="100%p"
    android:interpolator="@android:anim/accelerate_interpolator" >
</translate>


然后在模块的styles.xml中增加样式


<!--弹窗样式-->
    <style name="AnimationRightFade"><!--右侧-->
        <item name="android:windowEnterAnimation">@anim/in_right_to_left</item>  <!--打开动画-->
        <item name="android:windowExitAnimation">@anim/out_left_to_right</item>  <!--关闭动画-->
    </style>
    <style name="AnimationBottomFade"><!--底部-->
        <item name="android:windowEnterAnimation">@anim/in_bottom_to_top</item>
        <item name="android:windowExitAnimation">@anim/out_top_to_bottom</item>
    </style>


然后在模块的utils包中新建一个LiWindow类


202004051607307.png


代码如下:


package com.llw.mvplibrary.utils;
import android.app.Activity;
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.PopupWindow;
import com.llw.mvplibrary.R;
import java.util.HashMap;
import java.util.Map;
/**
 * 自定义弹窗
 */
public class LiWindow {
    private LiWindow mLiWindow;
    private PopupWindow mPopupWindow;
    private LayoutInflater inflater;
    private View mView;
    private Context mContext;
    private WindowManager show;
    WindowManager.LayoutParams context;
    private Map<String,Object> mMap = new HashMap<>();
    public Map<String, Object> getmMap() {
        return mMap;
    }
    public LiWindow(Context context){
        this.mContext = context;
        inflater = LayoutInflater.from(context);
        mLiWindow = this;
    }
    public LiWindow(Context context, Map<String,Object> map){
        this.mContext = context;
        this.mMap = map;
        inflater = LayoutInflater.from(context);
    }
    /**
     * 右侧显示  自适应大小
     * @param mView
     */
    public void showRightPopupWindow(View mView) {
        mPopupWindow = new PopupWindow(mView,
                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT , true);
        mPopupWindow.setContentView(mView);
        mPopupWindow.setOutsideTouchable(true);//点击空白处不关闭弹窗  true为关闭
        mPopupWindow.setFocusable(true);
        mPopupWindow.setAnimationStyle(R.style.AnimationRightFade); //设置动画
        mPopupWindow.showAtLocation(mView, Gravity.RIGHT,0 ,0);
        setBackgroundAlpha(0.5f,mContext);
        WindowManager.LayoutParams nomal = ((Activity) mContext).getWindow().getAttributes();
        nomal.alpha = 0.5f;
        ((Activity) mContext).getWindow().setAttributes(nomal);
        mPopupWindow.setOnDismissListener(closeDismiss);
    }
    /**
     * 右侧显示  高度占满父布局
     * @param mView
     */
    public void showRightPopupWindowMatchParent(View mView) {
        mPopupWindow = new PopupWindow(mView,
                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT , true);
        mPopupWindow.setContentView(mView);
        mPopupWindow.setOutsideTouchable(true);//点击空白处不关闭弹窗  true为关闭
        mPopupWindow.setFocusable(true);
        mPopupWindow.setAnimationStyle(R.style.AnimationRightFade); //设置动画
        mPopupWindow.showAtLocation(mView, Gravity.RIGHT,0 ,0);
        setBackgroundAlpha(0.5f,mContext);
        WindowManager.LayoutParams nomal = ((Activity) mContext).getWindow().getAttributes();
        nomal.alpha = 0.5f;
        ((Activity) mContext).getWindow().setAttributes(nomal);
        mPopupWindow.setOnDismissListener(closeDismiss);
    }
    /**
     * 底部显示
     * @param mView
     */
    public void showBottomPopupWindow(View mView) {
        mPopupWindow = new PopupWindow(mView,
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        mPopupWindow.setContentView(mView);
        mPopupWindow.setOutsideTouchable(true);//点击空白处不关闭弹窗  true为关闭
        mPopupWindow.setFocusable(true);
        mPopupWindow.setAnimationStyle(R.style.AnimationBottomFade); //设置动画
        mPopupWindow.showAtLocation(mView, Gravity.BOTTOM, 0, 0);
        setBackgroundAlpha(0.5f,mContext);
        WindowManager.LayoutParams nomal = ((Activity) mContext).getWindow().getAttributes();
        nomal.alpha = 0.5f;
        ((Activity) mContext).getWindow().setAttributes(nomal);
        mPopupWindow.setOnDismissListener(closeDismiss);
    }
    public static void setBackgroundAlpha(float bgAlpha,Context mContext){
        WindowManager.LayoutParams lp = ((Activity) mContext).getWindow().getAttributes();
        lp.alpha = bgAlpha;
        ((Activity) mContext).getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        ((Activity) mContext).getWindow().setAttributes(lp);
    }
    /**
     * 设置弹窗动画
     * @param animId
     * @return showPopu
     */
    public LiWindow setAnim(int animId) {
        if (mPopupWindow != null) {
            mPopupWindow.setAnimationStyle(animId);
        }
        return mLiWindow;
    }
    //弹窗消失时关闭阴影
    public PopupWindow.OnDismissListener closeDismiss = new PopupWindow.OnDismissListener() {
        @Override
        public void onDismiss() {
            WindowManager.LayoutParams nomal = ((Activity)mContext).getWindow().getAttributes();
            nomal.alpha = 1f;
            ((Activity)mContext).getWindow().setAttributes(nomal);
        }
    };
    public void closePopupWindow() {
        if (mPopupWindow != null) {
            mPopupWindow.dismiss();
        }
    }
    /*
        使用方法
    *   LiWindow liWindow = new LiWindow(MainActivity.this);
        View mView = LayoutInflater.from(MainActivity.this).inflate(R.layout.center_layout,null);
        liWindow.showCenterPopupWindow(mView);
    * */
}


弹窗也是需要布局文件的,现在创建一个新的布局文件,用于显示城市列表。


返回图标:


20200405164606575.png


在项目的layout下创建一个名为window_city_list.xml的布局文件

代码如下:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:fitsSystemWindows="true"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <LinearLayout
        android:orientation="vertical"
        android:background="#FFF"
        android:layout_width="240dp"
        android:layout_height="match_parent">
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <androidx.appcompat.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:contentInsetLeft="16dp"
                app:popupTheme="@style/AppTheme.PopupOverlay">
                <TextView
                    android:id="@+id/tv_title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:textSize="16sp"
                    android:textColor="#000"
                    android:text="中国" />
            </androidx.appcompat.widget.Toolbar>
            <!--城市列表的返回-->
            <ImageView
                android:visibility="gone"
                android:layout_marginLeft="@dimen/dp_10"
                android:layout_centerVertical="true"
                android:id="@+id/iv_back_city"
                android:src="@mipmap/icon_page_return"
                android:padding="15dp"
                android:layout_width="40dp"
                android:layout_height="40dp"/>
            <!--区/县列表的返回-->
            <ImageView
                android:visibility="gone"
                android:layout_marginLeft="@dimen/dp_10"
                android:layout_centerVertical="true"
                android:id="@+id/iv_back_area"
                android:src="@mipmap/icon_page_return"
                android:padding="15dp"
                android:layout_width="40dp"
                android:layout_height="40dp"/>
        </RelativeLayout>
        <View
            android:layout_width="match_parent"
            android:layout_height="0.5dp"
            android:background="#EEEEEE"/>
        <!--数据展示-->
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </LinearLayout>
</RelativeLayout>


为了让点击的时候有一个效果,在模块的res文件下的drawable下创建一个rounded_corners.xml的样式文件,点击的水波纹效果


20200405165319861.png


代码如下


<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <solid android:color="#18ffc400"/>
        </shape>
    </item>
    <item android:state_focused="true" android:state_enabled="true">
        <shape android:shape="rectangle">
            <solid android:color="#0f000000"/>
        </shape>
    </item>
</selector>


接下来在res文件下下新建一个drawable-v21的文件夹,文件夹下创建一个


bg_white.xml


20200405165514119.png


代码如下:


<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#20000000"
    android:drawable="@drawable/rounded_corners"/>


点击的样式做好了,接下来创建城市列表的item


在项目的layout文件夹下创建一个名为item_city_list.xml的布局文件


20200405165728527.png


代码如下:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_city"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#FFF"
    android:orientation="vertical">
    <!--显示省 、 市 、 区/县-->
    <TextView
        android:id="@+id/tv_city"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:foreground="@drawable/bg_white"
        android:gravity="center"
        android:padding="10dp"
        android:textColor="#FF000000"
        android:textSize="15sp" />
    <!--分隔线-->
    <View
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:background="#EEEEEE"/>
</LinearLayout>


接下来就是要创建一个实体Bean用来接收JSON中解析出来的城市数据,里面包含了省、市、区/县


在项目的bean包下新建一个CityResponse


20200405170253561.png


代码如下:


package com.llw.goodweather.bean;
import java.util.List;
public class CityResponse {
    /**
     * name : 北京市
     * city : [{"name":"北京市","area":["东城区","西城区","崇文区","宣武区","朝阳区","丰台区","石景山区","海淀区","门头沟区","房山区","通州区","顺义区","昌平区","大兴区","平谷区","怀柔区","密云县","延庆县"]}]
     */
    private String name;
    private List<CityBean> city;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<CityBean> getCity() {
        return city;
    }
    public void setCity(List<CityBean> city) {
        this.city = city;
    }
    public static class CityBean {
        /**
         * name : 北京市
         * area : ["东城区","西城区","崇文区","宣武区","朝阳区","丰台区","石景山区","海淀区","门头沟区","房山区","通州区","顺义区","昌平区","大兴区","平谷区","怀柔区","密云县","延庆县"]
         */
        private String name;
        private List<AreaBean> area;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public static class AreaBean {
            /**
             * name : 北京市
             * area : ["东城区","西城区","崇文区","宣武区","朝阳区","丰台区","石景山区","海淀区","门头沟区","房山区","通州区","顺义区","昌平区","大兴区","平谷区","怀柔区","密云县","延庆县"]
             */
            private String name;
            public String getName() {
                return name;
            }
            public void setName(String name) {
                this.name = name;
            }
        }
    }
}


接下来创建适配器,需要三个适配器,省、市、区/县。在adapter包下创建


ProvinceAdapterCityAdapterAreaAdapter


20200405171755476.png


ProvinceAdapter.java


package com.llw.goodweather.adapter;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.llw.goodweather.R;
import com.llw.goodweather.bean.CityResponse;
import java.util.List;
/**
 * 省列表适配器
 */
public class ProvinceAdapter extends BaseQuickAdapter<CityResponse, BaseViewHolder> {
    public ProvinceAdapter(int layoutResId, @Nullable List<CityResponse> data) {
        super(layoutResId, data);
    }
    @Override
    protected void convert(BaseViewHolder helper, CityResponse item) {
        helper.setText(R.id.tv_city,item.getName());//省名称
        helper.addOnClickListener(R.id.item_city);//点击之后进入市级列表
    }
}


CityAdapter.java


package com.llw.goodweather.adapter;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.llw.goodweather.R;
import com.llw.goodweather.bean.CityResponse;
import java.util.List;
/**
 * 市列表适配器
 */
public class CityAdapter extends BaseQuickAdapter<CityResponse.CityBean, BaseViewHolder> {
    public CityAdapter(int layoutResId, @Nullable List<CityResponse.CityBean> data) {
        super(layoutResId, data);
    }
    @Override
    protected void convert(BaseViewHolder helper, CityResponse.CityBean item) {
        helper.setText(R.id.tv_city,item.getName());//市名称
        helper.addOnClickListener(R.id.item_city);//点击事件  点击进入区/县列表
    }
}
相关文章
|
3月前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
278 0
安卓项目:app注册/登录界面设计
|
7天前
|
Dart 前端开发 Android开发
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
24天前
|
存储 监控 API
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
|
4月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
166 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
4月前
|
存储 开发工具 Android开发
使用.NET MAUI开发第一个安卓APP
【9月更文挑战第24天】使用.NET MAUI开发首个安卓APP需完成以下步骤:首先,安装Visual Studio 2022并勾选“.NET Multi-platform App UI development”工作负载;接着,安装Android SDK。然后,创建新项目时选择“.NET Multi-platform App (MAUI)”模板,并仅针对Android平台进行配置。了解项目结构,包括`.csproj`配置文件、`Properties`配置文件夹、平台特定代码及共享代码等。
389 2
|
4月前
|
XML Android开发 数据格式
🌐Android国际化与本地化全攻略!让你的App走遍全球无障碍!🌍
在全球化背景下,实现Android应用的国际化与本地化至关重要。本文以一款旅游指南App为例,详细介绍如何通过资源文件拆分与命名、适配布局与方向、处理日期时间及货币格式、考虑文化习俗等步骤,完成多语言支持和本地化调整。通过邀请用户测试并收集反馈,确保应用能无缝融入不同市场,提升用户体验与满意度。
161 3
|
4月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android应用开发中的多线程编程,涵盖基本概念、常见实现方式及最佳实践。主要内容包括主线程与工作线程的作用、多线程的多种实现方法(如 `Thread`、`HandlerThread`、`Executors` 和 Kotlin 协程),以及如何避免内存泄漏和合理使用线程池。通过有效的多线程管理,可以显著提升应用性能和用户体验。
134 10
|
3月前
|
安全 网络安全 Android开发
深度解析:利用Universal Links与Android App Links实现无缝网页至应用跳转的安全考量
【10月更文挑战第2天】在移动互联网时代,用户经常需要从网页无缝跳转到移动应用中。这种跳转不仅需要提供流畅的用户体验,还要确保安全性。本文将深入探讨如何利用Universal Links(仅限于iOS)和Android App Links技术实现这一目标,并分析其安全性。
502 0
|
4月前
|
XML 数据库 Android开发
10分钟手把手教你用Android手撸一个简易的个人记账App
该文章提供了使用Android Studio从零开始创建一个简单的个人记账应用的详细步骤,包括项目搭建、界面设计、数据库处理及各功能模块的实现方法。
|
5月前
|
Android开发 iOS开发 C#
Xamarin:用C#打造跨平台移动应用的终极利器——从零开始构建你的第一个iOS与Android通用App,体验前所未有的高效与便捷开发之旅
【8月更文挑战第31天】Xamarin 是一个强大的框架,允许开发者使用单一的 C# 代码库构建高性能的原生移动应用,支持 iOS、Android 和 Windows 平台。作为微软的一部分,Xamarin 充分利用了 .NET 框架的强大功能,提供了丰富的 API 和工具集,简化了跨平台移动应用开发。本文通过一个简单的示例应用介绍了如何使用 Xamarin.Forms 快速创建跨平台应用,包括设置开发环境、定义用户界面和实现按钮点击事件处理逻辑。这个示例展示了 Xamarin.Forms 的基本功能,帮助开发者提高开发效率并实现一致的用户体验。
214 0

热门文章

最新文章