在ActionBar添加刷新Loading状态

ActionBar刷新动画实现
本文介绍了一种在Android应用中实现ActionBar刷新动画的方法。通过自定义Menu项和ProgressBar布局,结合Activity代码逻辑,可在列表等组件下拉刷新时展示加载动画。此方案适用于3.0及以上版本,并利用ActionbarSherlock实现向下兼容。

应用场景:在界面内列表或其他部件下拉刷新时,ActionBar 出现一个转圈的刷新标示动画。 

实现方式:可使用开源类库 RefreshActionItem (https://github.com/ManuelPeinado/RefreshActionItem),RefreshActionItem 还支持一些扩展功能,功能比较丰富;

如果只需要实现一个刷新和Loading的效果,则可以使用另一种简便的实现方式:

1. 首先定义一个 Menu xml 文件, share_public.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/refresh_loading"
        android:icon="@color/transparent"
        android:showAsAction="always"
        android:title="刷新"/>

</menu>


2. 然后创建一个代表刷新进度的自定义 ProgressBar 布局文件 actionbar_indeterminate_progress.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="56dp"
    android:minWidth="56dp">
 
    <ProgressBar android:layout_width="32dp"
        android:layout_height="32dp"
        android:layout_gravity="center"
        style="?indeterminateProgressStyle" />
</FrameLayout>

注意,为了显示美观,上面的 宽度和高度 不同的版本和屏幕可能需要设置不一样的值,可以在不同的 dimens.xml 中设置。


3. 在 Activity 代码中,获取到该 MenuItem 并根据刷新情况来设置 ActionView:

	MenuItem mProgressMenu;

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getSupportMenuInflater().inflate(R.menu.share_public, menu);
		mProgressMenu = menu.findItem(R.id.refresh_loading);
		return true;
	}

	public void setLoadingState(boolean refreshing) {
		if (mProgressMenu != null) {
			if (refreshing) {
				mProgressMenu
						.setActionView(R.layout.actionbar_indeterminate_progress);
				mProgressMenu.setVisible(true);
			} else {
				mProgressMenu.setVisible(false);
				mProgressMenu.setActionView(null);
			}
		}
	}
现在根据刷新逻辑,只需调用setLoadingState方法就可以启用刷新动画了。


本项目不在 ActionView 中处理 OnClick 事件,用户点击该菜单是没响应的,采用此种方式,loading状态动画只会在刷新时进行,在刷新结束后隐藏。



注:本帖系在参考地址基础上改造,本项目使用了ActionbarSherlock来兼容3.0以下的版本中的Actionbar;

参考地址使用了AppCompat作兼容,在处理添加ActionView操作上略有不同。

参考地址Read more: http://blog.chengyunfeng.com/?p=572



<template> <view class=""> <!-- <uni-nav-bar :style="{ position: 'fixed', width: '100%', float: 'left', zIndex: ' 10086', height: '44px', marginTop: '-' + titleHei + '44px', paddingTop: titleHei, backgroundColor: 'rgb(50,133,236) ' }" left-icon="left" right-icon="search" color="white" @clickLeft="clickLeftTitle" @clickRight="clickRightTitle" title="进场管理" background-color="rgb(50,133,236)" /> <view class="" :style="{ height: '44px' }"></view> --> <ActionBar :pageInfo="pageInfo" :showSearch="true" @search="handleSearchClick" /> <view class="bodyClass" v-for="(item, index) in infoList" :key="index" v-show="searchClick"> <div class="titleClass"> <uni-list> <uni-section style="font-size: 16px" :title="item.F_ProjectName?item.F_ProjectName:'项目名称'" type="line"></uni-section> </uni-list> </div> <div class="contentClassMiddle"> <view @click="goNext(item.F_Id)"> <div class="conterContent">要求到岗时间:{{item.F_PlanEnterDate|timeFilter}}</div> <div class="conterContent flex-row-between"> <span>岗位/专业:{{getOptText(item.F_PostCode,BasePostMajor)}}</span> <text>学历:{{ getOptText(item.F_AreaEdu,AreaEdu)}}</text> </div> <div class="conterContent flex-row-between"> <span>年龄:{{getOptText(item.F_AreaAge,AreaAge)}}</span> <text>需求人数:{{item.F_UserCount}}</text> </div> <div class="conterContent flex-row-between"> <span>职称:{{getOptText(item.F_TechnicalTitle,AreaTechnicalTitle)}}</span> <text>调配人数:{{item.F_UserInCount}}</text> </div> <div class="conterContent flex-row-between"> <span>持证:{{getOptText(item.F_Credentials,AreaCredentials)}}</span> <text>招聘人数:{{item.F_RecruitCount}}</text> </div> </view> <div class="buttonCLassBoFd row-flex" style="margin-top: 4%;"> <span class="buttonCLassBo" style="color:#409EFF;font-size: 16px;" @click="goRetreat(item)"> <l-icon slot="suffix" type='sort'></l-icon> 退场人员 </span> <span class="borderClass"></span> <span class="buttonCLassBo" style="color:orange;font-size: 16px;cursor:pointer;" @click.stop="goPeople(item)"> <l-icon slot="suffix" type='edit'></l-icon> <span style="margin-left: 2%;">待岗人员</span> </span> <span class="borderClass"></span> <!-- <span class="buttonCLassBo" style="color:red;font-size: 16px;cursor:pointer;" @click.stop="goAudit(item)"> <l-icon slot="suffix" type='post'></l-icon> <span style="margin-left: 2%;">发布招聘</span> </span> --> <span class="buttonCLassBo" style="color:red;font-size: 16px;cursor:pointer;" @click.stop="goAudit(item)" v-if="item.F_UserCount > (item.F_UserInCount + item.F_RecruitCount)"> <l-icon slot="suffix" type='post'></l-icon> <span style="margin-left: 2%;">发布招聘</span> </span> <span class="buttonCLassBo" style="color:lightgray;font-size: 16px;cursor:default;" v-else> <l-icon slot="suffix" type='post'></l-icon> <span style="margin-left: 2%;">发布招聘</span> </span> </div> </div> </div> <!-- <div class="contentClassRight" @click="goNext(item.F_Id)"></div> --> </view> <view style="width:100%;clear: both;" v-show="searchClick"> <uni-load-more :status="status"></uni-load-more> </view> <!-- <view style="padding: 6% 6% 0 6%" v-show="!searchClick"> <l-select :range="BasePostMajor" title="岗位专业" placeholder="请选择岗位专业" right v-model="queryJson.F_PostCode" /> <l-select :range="Deps" title="项目名称" placeholder="请选择项目名称" right v-model="queryJson.F_ProjectId" /> <picker mode="date" fields="day" :value="queryJson.F_PlanEnterDate" @change="bindDateChange"> <l-input title="要求到岗时间" right v-model="queryJson.F_PlanEnterDate" placeholder="请选择到岗时间" /> </picker> <br /> <view class="padding-lr bg-white margin-tb padding-tb"> <l-button class="block" size="lg" color="blue" block @click="handleSearch()">确定</l-button> <br /> <l-button class="block" size="lg" color="red" block @click="cancelCLikck">取消</l-button> </view> </view> --> <view class="side-mask" :class="{'show': sideOpen}" @click="sideOpen = false"></view> <view class="side-filter" :class="{'show': sideOpen}"> <scroll-view scroll-y class="filter-content"> <view class="filter-header"> <text class="filter-title">筛选条件</text> <l-icon type="close" size="36rpx" color="#999" @click="sideOpen = false" class="close-icon" /> </view> <view class="filter-body"> <view class="filter-item"> <l-select :range="BasePostMajor" title="岗位专业" placeholder="请选择岗位专业" right v-model="queryJson.F_PostCode" /> </view> <view class="filter-item"> <l-select :range="Deps" title="项目名称" placeholder="请选择项目名称" right v-model="queryJson.F_ProjectId" /> </view> <view class="filter-item"> <picker mode="date" fields="day" :value="queryJson.F_PlanEnterDate" @change="bindDateChange"> <l-input title="要求到岗时间" right v-model="queryJson.F_PlanEnterDate" placeholder="请选择到岗时间" /> </picker> </view> <view class="filter-actions"> <l-button class="reset-btn" @click="reset" plain> 重置条件 </l-button> <l-button class="confirm-btn" @click="handleConfirm" type="primary"> 确定筛选 </l-button> </view> </view> </scroll-view> </view> </view> </template> <script> import ActionBar from '@/components/action-bar.vue' export default { components: { ActionBar }, data() { return { infoList: [], searchClick: true, create: '', userId: '', status: "loading", currentPage: 1, size: 10, pageCount: 1, BasePostMajor: [], AreaAge: [], AreaEdu: [], F_TechnicalTitle: [], AreaCredentials: [], defaultQueryJson: {}, queryJson: { F_ByBusinessId: this.$store.state.user.departmentId }, Deps: [], sideOpen: false, pageInfo: '加载中...', searchClick: true, }; }, async onLoad({ type, id }) { const sysInfo = uni.getSystemInfoSync(); this.titleHei = sysInfo.statusBarHeight + 'px'; this.contentHei = this.contentHei + sysInfo.statusBarHeight + 'px'; this.getDataSource("BasePostMajor"); // await this.init(type, id); uni.$on('awaitEtl', function(data) { if (data == 2) { this.getList(); } }) this.defaultQueryJson = { ...this.queryJson } this.getProjects("Deps") this.getList(); this.initOptions() }, onReachBottom() { if (this.currentPage < this.pageCount && this.status !== "loading") { this.status = "loading"; // 开始加载时设置状态 this.currentPage++; this.getList(); } else { this.status = "nomore"; } }, onShow() { this.getList(1) }, filters: { statusFilter(v) { if (v == 1) { return "审核中"; } else if (v == 2) { return "已审核"; } else { return "待审核"; } }, timeFilter(v) { if (v) { return v.substring(0, 10); } return "-"; } }, methods: { handleSearchClick() { this.sideOpen = true; }, reset() { this.queryJson = { ...this.defaultQueryJson }; this.getList(1); }, async handleConfirm() { this.sideOpen = false; await this.getList(1); }, bindDateChange: function(e) { this.$set(this.queryJson, 'F_PlanEnterDate', e.detail.value); }, clickLeftTitle() { const pages = getCurrentPages(); // 有可返回的页面则直接返回,uni.navigateBack 默认返回失败之后会自动刷新页面 ,无法继续返回 if (pages.length > 1) { uni.navigateBack(1); return; } else { uni.reLaunch({ url: '/pages/home' }); return; } }, initOptions() { this.getOpts('AreaAge,AreaEdu,AreaTechnicalTitle,CertifcateCategory,AreaCredentials'); }, async init(type, id) { await uni.request({ url: this.apiRoot + '/user/become/getdata', header: this.headers, data: { ...this.auth, data: this.$store.state.user.userId } }).then(([err, res]) => { console.log(err, 'err'); console.log(res, 'res'); }) }, getList(num) { let queryJson = this.queryJson if (num) { this.currentPage = num; } uni.request({ url: this.apiRoot + "/career/enter/postpagelist", header: this.headers, method: "post", data: { ...this.auth, data: { "pagination": { "rows": this.size, "page": this.currentPage, "sidx": "", "sord": "" }, "queryJson": JSON.stringify(queryJson) } } }).then(([err, res]) => { this.status = ""; let result = res.data; if (result.data && result.data.rows) { result.data.rows.map(item => { item.F_OptStatus = item.F_OptStatus == null ? "0" : item.F_OptStatus; }) this.infoList = this.infoList.concat(result.data.rows); // this.infoList.push(...result.data.rows); this.pageCount = result.data.total; this.pageInfo = `共 ${result.data.records} 条,当前 ${result.data.page}/${result.data.total} 页` if (this.currentPage >= this.pageCount) { this.status = "nomore"; } } }) }, clickRightTitle() { this.searchClick = !this.searchClick; }, cancelCLikck() { this.searchClick = true; }, goNext(id) { uni.navigateTo({ url: '../enterPlan/listDetail?id=' + id // url: '../enterPlan/approachPlanDetail?id=' + id }); }, goPlan(id) { }, goPeople(obj) { this.setPageParam(obj); uni.navigateTo({ url: './awaitEtList?id=' + obj.F_Id // url: `./?type=create&id=this.userId` }); }, goRetreat(obj) { this.setPageParam(obj); uni.navigateTo({ url: './retreatEtList?id=' + obj.F_Id }); }, goAudit(item) { uni.navigateTo({ url: './recruitAudit?id=' + item.F_Id }); } } }; </script> <style scoped lang="less"> /* 基础样式 */ .page-container { position: relative; background-color: #f5f7fa; overflow: hidden; padding: 0px; } .bodyClass { min-height: 16vh; float: left; width: 96%; margin-top: 2%; margin-left: 2%; padding: 2%; border: 1px #cccac6 solid; border-radius: 10px; position: relative; .titleClassLeft { height: 20%; width: 10%; float: left; text-align: center; position: relative; .leftImg { display: flex; position: absolute; margin: auto; right: 0; left: 0; top: 0; bottom: 0; background-color: #2086df; height: 80%; width: 20%; } } .titleClass { // height: 20%; width: 100%; margin-left: 2%; // float: right; // line-height: 4vh; } .contentClassLeft { height: 72%; width: 30%; margin-left: 2%; float: left; } .contentClassMiddle { display: grid; width: 86%; margin-left: 4%; margin-top: 2%; float: left; .conterContent { margin-top: 4%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; overflow: hidden; } .buttonCLassBo { margin: 2%; display: inline-block; width: 45%; text-align: center; } } .contentClassRight { width: 6%; margin-top: 12vh; float: left; width: 12px; height: 12px; background-color: transparent; border-color: #cccac6; border-style: solid; border-width: 2px 2px 0 0; -webkit-transform: rotate(45deg); transform: rotate(45deg); } } .titleRightText { right: 4%; z-index: 2000000000000000; color: #000; } .trapezoid { color: white; font-size: 10px; position: absolute; width: 34px; height: 0; border-right: 26px solid transparent; border-bottom: 25px solid green; border-left: 25px solid transparent; -webkit-transform: rotate(54deg); transform: rotate(46deg); right: -22px; top: 9px; text-align: center; } .trapezoid0 { border-bottom: 25px solid #F95E5A; } .trapezoid1 { border-bottom: 25px solid #FF9900; } .trapezoid2 { border-bottom: 25px solid #409EFF; } .uni-list[data-v-5009d455] { position: static; /deep/.uni-section .uni-section-header[data-v-f7ca1098] { padding: 0; font-size: 16px; font-weight: 700; } } .flex-between { display: flex; justify-content: space-between; } .w80 { width: 80%; margin: 10px auto; } .flex-row { display: flex; clear: both; justify-content: space-around; align-items: center; } .grey-line { height: 16px; width: 1px; background-color: #797979; } .orange-word { color: #f59a23; } .blue-word { color: #409eff; } ::v-deep .uni-list--border-top { height: 0px !important; background-color: transparent !important; border: none !important; } ::v-deep .uni-list--border-bottom { height: 0px !important; background-color: transparent !important; border: none !important; } </style>bug修改
10-17
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值