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);//点击事件  点击进入区/县列表
    }
}
相关文章
|
11月前
|
Android开发 UED 计算机视觉
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
本文介绍了一款受游戏“金铲铲之战”启发的Android自定义View——线条等待动画的实现过程。通过将布局分为10份,利用`onSizeChanged`测量最小长度,并借助画笔绘制动态线条,实现渐变伸缩效果。动画逻辑通过四个变量控制线条的增长与回退,最终形成流畅的等待动画。代码中详细展示了画笔初始化、线条绘制及动画更新的核心步骤,并提供完整源码供参考。此动画适用于加载场景,提升用户体验。
669 5
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
|
11月前
|
Android开发
Android自定义view之利用PathEffect实现动态效果
本文介绍如何在Android自定义View中利用`PathEffect`实现动态效果。通过改变偏移量,结合`PathEffect`的子类(如`CornerPathEffect`、`DashPathEffect`、`PathDashPathEffect`等)实现路径绘制的动态变化。文章详细解析了各子类的功能与参数,并通过案例代码展示了如何使用`ComposePathEffect`组合效果,以及通过修改偏移量实现动画。最终效果为一个菱形图案沿路径运动,源码附于文末供参考。
207 0
|
11月前
|
Android开发 开发者
Android自定义view之利用drawArc方法实现动态效果
本文介绍了如何通过Android自定义View实现动态效果,重点使用`drawArc`方法完成圆弧动画。首先通过`onSizeChanged`进行测量,初始化画笔属性,设置圆弧相关参数。核心思路是不断改变圆弧扫过角度`sweepAngle`,并调用`invalidate()`刷新View以实现动态旋转效果。最后附上完整代码与效果图,帮助开发者快速理解并实践这一动画实现方式。
249 0
|
11月前
|
XML Java Android开发
Android自定义view之网易云推荐歌单界面
本文详细介绍了如何通过自定义View实现网易云音乐推荐歌单界面的效果。首先,作者自定义了一个圆角图片控件`MellowImageView`,用于绘制圆角矩形图片。接着,通过将布局放入`HorizontalScrollView`中,实现了左右滑动功能,并使用`ViewFlipper`添加图片切换动画效果。文章提供了完整的代码示例,包括XML布局、动画文件和Java代码,最终展示了实现效果。此教程适合想了解自定义View和动画效果的开发者。
455 65
Android自定义view之网易云推荐歌单界面
|
11月前
|
XML 前端开发 Android开发
一篇文章带你走近Android自定义view
这是一篇关于Android自定义View的全面教程,涵盖从基础到进阶的知识点。文章首先讲解了自定义View的必要性及简单实现(如通过三个构造函数解决焦点问题),接着深入探讨Canvas绘图、自定义属性设置、动画实现等内容。还提供了具体案例,如跑马灯、折线图、太极图等。此外,文章详细解析了View绘制流程(measure、layout、draw)和事件分发机制。最后延伸至SurfaceView、GLSurfaceView、SVG动画等高级主题,并附带GitHub案例供实践。适合希望深入理解Android自定义View的开发者学习参考。
838 84
|
6月前
|
人工智能 小程序 搜索推荐
【一步步开发AI运动APP】十二、自定义扩展新运动项目2
本文介绍如何基于uni-app运动识别插件实现“双手并举”自定义扩展运动,涵盖动作拆解、姿态检测规则构建及运动分析器代码实现,助力开发者打造个性化AI运动APP。
|
11月前
|
前端开发 Android开发 UED
讲讲Android为自定义view提供的SurfaceView
本文详细介绍了Android中自定义View时使用SurfaceView的必要性和实现方式。首先分析了在复杂绘制逻辑和高频界面更新场景下,传统View可能引发卡顿的问题,进而引出SurfaceView作为解决方案。文章通过Android官方Demo展示了SurfaceView的基本用法,包括实现`SurfaceHolder.Callback2`接口、与Activity生命周期绑定、子线程中使用`lockCanvas()`和`unlockCanvasAndPost()`方法完成绘图操作。
302 3
|
11月前
|
Android开发 开发者
Android自定义view之围棋动画(化繁为简)
本文介绍了Android自定义View的动画实现,通过两个案例拓展动态效果。第一个案例基于`drawArc`方法实现单次动画,借助布尔值控制动画流程。第二个案例以围棋动画为例,从简单的小球直线运动到双向变速运动,最终实现循环动画效果。代码结构清晰,逻辑简明,展示了如何化繁为简实现复杂动画,帮助读者拓展动态效果设计思路。文末提供完整源码,适合初学者和进阶开发者学习参考。
198 0
Android自定义view之围棋动画(化繁为简)
|
10月前
《仿盒马》app开发技术分享-- 自定义标题栏&商品详情初探(9)
上一节我们实现了顶部toolbar的地址选择,会员码展示,首页的静态页面就先告一段落,这节我们来实现商品列表item的点击传值、自定义标题栏。
122 0
|
11月前
|
Java Android开发 开发者
Android自定义view之围棋动画
本文详细介绍了在Android中自定义View实现围棋动画的过程。从测量宽高、绘制棋盘背景,到创建固定棋子及动态棋子,最后通过属性动画实现棋子的移动效果。文章还讲解了如何通过自定义属性调整棋子和棋盘的颜色及动画时长,并优化视觉效果,如添加渐变色让白子更明显。最终效果既可作为围棋动画展示,也可用作加载等待动画。代码完整,适合进阶开发者学习参考。
236 0

热门文章

最新文章