首页 文章 精选 留言 我的

精选列表

搜索[内核任意读写],共10009篇文章
优秀的个人博客,低调大师

Android粒子爆炸特效[可用于任意控件]

小米手机用户可以看到,小米手机在应用卸载时会有一个粒子爆炸的特效效果,对此类动画效果垂涎已久,奈何一直没有机会用。正好最近项目里需要用到粒子爆炸的特效,于是便抽时间自己也试着仿写了一个效果出来。 先看下效果: How to use: **Step 1. Add the JitPack repository to your build fileAdd it in your root build.gradle at the end of repositories: allprojects { repositories { ... maven { url 'https://jitpack.io' } } } Step 2.Add the dependency dependencies { compile 'com.github.zhaolei9527:Particle-master:v1.0.1' } 代码中这样使用: 首先提供了响应式触发的方式,首先进行埋雷,当控件被点击时,触发爆炸。是不是很刺激? //目前提供了六种的粒子爆炸特效 explosionSite1 = new ExplosionSite(this, new BooleanFactory()); explosionSite2 = new ExplosionSite(this, new ExplodeParticleFactory()); explosionSite3 = new ExplosionSite(this, new FallingParticleFactory()); explosionSite4 = new ExplosionSite(this, new FlyawayFactory()); explosionSite5 = new ExplosionSite(this, new InnerFallingParticleFactory()); explosionSite6 = new ExplosionSite(this, new VerticalAscentFactory()); //爆炸激活方式一:将View或ViewGroup添加至雷管监听,View被点击时,触发爆炸 explosionSite1.addListener(img_1); explosionSite2.addListener(img_2); explosionSite3.addListener(img_6); explosionSite4.addListener(img_4); explosionSite5.addListener(img_5); explosionSite6.addListener(img_3); 其次针对一些情况,提供了另外一种直接的触发方式。是不是更刺激? //爆炸激活方式二:将View或ViewGroup直接点燃爆炸 explosionSite1.explode(img_1); explosionSite2.explode(img_2); explosionSite3.explode(img_3); explosionSite4.explode(img_4); explosionSite5.explode(img_5); explosionSite6.explode(img_6); 看下原理:GitHub项目地址网上实现类似相同效果的很多,基本规则也都差不多。主要对象如下:ExplosionSite:爆炸效果发生的场地,是一个View。当一个控件需要爆炸时,需要为控件生成一个ExplosionSite,这个ExplosionSite覆盖整个屏幕,于是我们才能看到完整的爆炸效果,在ExplosionField的构造函数中,传入不同的ParticleFactory,就可以生成不同的爆炸效果。 ExplosionAnimator:爆炸动画,其实是一个计时器,继承自ValueAnimator。0x400s内,完成爆炸动画,每次计时,就更新所有粒子的运动状态。draw()方法是它最重要的方法,也就是使所有粒子重绘自身,从而实现动画效果。 ParticleFactory:是一个抽象类。用于产生粒子数组,不同的ParticleFactory可以产生不同类型的粒子数组。 Particle:抽象的粒子类。代表粒子本身,必须拥有的属性包括,当前自己的cx,cy坐标和颜色color。必须实现两个方法,draw()方法选择怎么绘制自身(圆形还是方形等),caculate()计算当前时间,自己所处的位置。 实现原理:1、获取当前控件背景bitmap例如,例子中使用的是imageview,对于控件,在Utils中提供有一个工具类,可以获得其背景的Bitmap对象 public static Bitmap createBitmapFromView(View view) { view.clearFocus(); Bitmap bitmap = createBitmapSafely(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888, 1); if (bitmap != null) { synchronized (sCanvas) { Canvas canvas = sCanvas; canvas.setBitmap(bitmap); view.draw(canvas); canvas.setBitmap(null); } } return bitmap; } public static Bitmap createBitmapSafely(int width, int height, Bitmap.Config config, int retryCount) { try { return Bitmap.createBitmap(width, height, config); } catch (OutOfMemoryError e) { e.printStackTrace(); if (retryCount > 0) { System.gc(); return createBitmapSafely(width, height, config, retryCount - 1); } return null; } } 2、将View镜像转换成粒子对象获取Bitmap以后,我们交给工厂对象进行加工,根据Bitmap生产Particle数组。我们知道Bitmap可以看成是一个像素矩阵,矩阵上面的点,就是一个个带有颜色的像素,于是我们可以获取到每个点的颜色和位置,组装成一个对象Particle,这么一来,Particle就代表带有颜色的点了。 public abstract class ParticleFactory { public abstract Particle[][] generateParticles(Bitmap bitmap, Rect bound); } 简单来说都一样,就是拿要爆炸的View制作一个镜像出来然后返回。 然后来看一个粒子效果的具体实现。 public Particle[][] generateParticles(Bitmap bitmap, Rect bound) { int w = bound.width(); int h = bound.height(); int partW_Count = w / PART_WH; //横向个数 int partH_Count = h / PART_WH; //竖向个数 int bitmap_part_w = bitmap.getWidth() / partW_Count; int bitmap_part_h = bitmap.getHeight() / partH_Count; Particle[][] particles = new Particle[partH_Count][partW_Count]; for (int row = 0; row < partH_Count; row ++) { //行 for (int column = 0; column < partW_Count; column ++) { //列 //取得当前粒子所在位置的颜色 int color = bitmap.getPixel(column * bitmap_part_w, row * bitmap_part_h); float x = bound.left + BooleanFactory.PART_WH * column; float y = bound.top + BooleanFactory.PART_WH * row; particles[row][column] = new BooleanParticle(color,x,y,bound); } } return particles; } 很简单,其中Rect类型的bound,是代表原来View控件的宽高信息。 根据我们设定的每个粒子的大小,和控件的宽高,我们就可以计算出,有多少个粒子组成这个控件的背景。 我们取得每个粒子所在位置的颜色,位置,用于生产粒子,这就是BooleanParticle。 3、爆炸对象及主要流程 public class ExplosionSite extends View { private static final String TAG = "ExplosionField"; private ArrayList<ExplosionAnimator> explosionAnimators; private HashMap<View, ExplosionAnimator> explosionAnimatorsMap; private OnClickListener onClickListener; private ParticleFactory mParticleFactory; public ExplosionSite(Context context, ParticleFactory particleFactory) { super(context); init(particleFactory); } public ExplosionSite(Context context, AttributeSet attrs, ParticleFactory particleFactory) { super(context, attrs); init(particleFactory); } private void init(ParticleFactory particleFactory) { explosionAnimators = new ArrayList<ExplosionAnimator>(); explosionAnimatorsMap = new HashMap<View, ExplosionAnimator>(); mParticleFactory = particleFactory; attach2Activity((Activity) getContext()); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (ExplosionAnimator animator : explosionAnimators) { animator.draw(canvas); } } /** * 爆破 * * @param view 使得该view爆破 */ public void explode(final View view) { //防止重复点击 if (explosionAnimatorsMap.get(view) != null && explosionAnimatorsMap.get(view).isStarted()) { return; } if (view.getVisibility() != View.VISIBLE || view.getAlpha() == 0) { return; } final Rect rect = new Rect(); view.getGlobalVisibleRect(rect); //得到view相对于整个屏幕的坐标 int contentTop = ((ViewGroup) getParent()).getTop(); Rect frame = new Rect(); ((Activity) getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); int statusBarHeight = frame.top; rect.offset(0, -contentTop - statusBarHeight);//去掉状态栏高度和标题栏高度 if (rect.width() == 0 || rect.height() == 0) { return; } //震动动画 ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f).setDuration(150); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { Random random = new Random(); @Override public void onAnimationUpdate(ValueAnimator animation) { view.setTranslationX((random.nextFloat() - 0.5f) * view.getWidth() * 0.05f); view.setTranslationY((random.nextFloat() - 0.5f) * view.getHeight() * 0.05f); } }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); explode(view, rect); } }); animator.start(); } private void explode(final View view, Rect rect) { final ExplosionAnimator animator = new ExplosionAnimator(this, Utils.createBitmapFromView(view), rect, mParticleFactory); explosionAnimators.add(animator); explosionAnimatorsMap.put(view, animator); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { //缩小,透明动画 view.animate().setDuration(150).scaleX(0f).scaleY(0f).alpha(0f).start(); } @Override public void onAnimationEnd(Animator animation) { view.animate().alpha(1f).scaleX(1f).scaleY(1f).setDuration(150).start(); //动画结束时从动画集中移除 explosionAnimators.remove(animation); explosionAnimatorsMap.remove(view); animation = null; } }); animator.start(); } /** * 给Activity加上全屏覆盖的ExplosionField */ private void attach2Activity(Activity activity) { ViewGroup rootView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT); ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); rootView.addView(this, lp); } /** * 希望谁有破碎效果,就给谁加Listener * * @param view 可以是ViewGroup */ public void addListener(View view) { if (view instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) view; int count = viewGroup.getChildCount(); for (int i = 0; i < count; i++) { addListener(viewGroup.getChildAt(i)); } } else { view.setClickable(true); view.setOnClickListener(getOnClickListener()); } } private OnClickListener getOnClickListener() { if (null == onClickListener) { onClickListener = new OnClickListener() { @Override public void onClick(View v) { ExplosionSite.this.explode(v); } }; } return onClickListener; } } 总结:总体来说实现很简单,就是根据工厂类,生成粒子数组。 而其实质是一个ValueAnimator,在一定时间内,从0数到1。 然后提供了一个draw()方法,方法里面调用了每个粒子的advance()方法,并且传入了当前数到的数字。 advance()方法里,其实调用了draw()方法和caculate()方法。 上面的实现,其实是一个固定的流程,添加了爆炸场地以后,我们就开始从0数到1,在这个过程中,粒子会根据当前时间,绘制自己的位置,所以粒子的位置,其实是它自己决定的,和流程无关。 也就是说,我们只要用不同的算法,绘制粒子的位置即可,实现了流程和粒子运动的分离。所以除了提供的六种爆炸特效之外,只要遵循这个原则,就能生成更多的粒子爆炸特效。 有了需求才有了功能,有了想法才有了创作,你的反馈会是使我进步的最大动力。觉得还不够方便?还想要什么功能?告诉我!欢迎反馈,欢迎Star。源码入口:GitHub项目地址

优秀的个人博客,低调大师

queryDsl多表联合查询,任意查询联合字段

这是我的通用方法 package com.spark.bitrade.service.Base; import com.querydsl.core.Tuple; import com.querydsl.core.types.EntityPath; import com.querydsl.core.types.Expression; import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.EntityPathBase; import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import com.spark.bitrade.pagination.PageListMapResult; import com.spark.bitrade.pagination.PageResult; import com.spark.bitrade.pagination.QueryDslContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * @author rongyu * @description * @date 2018/1/18 10:29 */ @Component public class BaseService<T> { //JPA查询工厂 @Autowired protected JPAQueryFactory queryFactory; @Autowired protected JPAQueryFactory jpaQueryFactory; @Autowired @PersistenceContext protected EntityManager em; /** * 查询列表 * * @param pageNo 分页参数 * @param pageSize 分页大小 * @param predicateList 查询条件 * @param entityPathBase 查询表 * @param orderSpecifierList 排序条件 * @return */ @Transactional(readOnly = true) public PageResult<T> queryDsl(Integer pageNo, Integer pageSize, List<Predicate> predicateList, EntityPathBase<T> entityPathBase, List<OrderSpecifier> orderSpecifierList) { List<T> list; //查询表 JPAQuery<T> jpaQuery = jpaQueryFactory.selectFrom(entityPathBase); //查询条件 if (predicateList != null && predicateList.size() > 0) jpaQuery.where(predicateList.toArray(new Predicate[predicateList.size()])); //排序方式 if (orderSpecifierList != null && orderSpecifierList.size() > 0) jpaQuery.orderBy(orderSpecifierList.toArray(new OrderSpecifier[orderSpecifierList.size()])); //分页查询 if (pageNo != null && pageSize != null) { list = jpaQuery.offset((pageNo - 1) * pageSize).limit(pageSize).fetch(); } else { list = jpaQuery.fetch(); } return new PageResult<>(list, pageNo, pageSize, jpaQuery.fetchCount()); } /** * 查询单个 * * @param predicate 查询条件 * @param entityPathBase 查询表 * @return */ @Transactional(readOnly = true) public T queryOneDsl(Predicate predicate, EntityPathBase<T> entityPathBase) { return jpaQueryFactory.selectFrom(entityPathBase).where(predicate).fetchFirst(); } //多表联合查询 /** * * @param qdc queryDsl 查询对象 * @param pageNo * @param pageSize * @return */ @Transactional(readOnly = true) public PageListMapResult queryDslForPageListResult(QueryDslContext qdc, Integer pageNo, Integer pageSize) { JPAQuery<Tuple> jpaQuery = queryFactory.select(qdc.expressionToArray()) .from(qdc.entityPathToArray()) .where(qdc.predicatesToArray()); List<Tuple> tuples = jpaQuery.orderBy(qdc.orderSpecifiersToArray()) .offset((pageNo - 1) * pageSize).limit(pageSize) .fetch(); List<Map<String, Object>> list = new LinkedList<>();//返回结果 //封装结果 for (int i = 0; i < tuples.size(); i++) { //遍历tuples Map<String, Object> map = new LinkedHashMap<>();//一条信息 for (Expression expression : qdc.getExpressions()) { map.put(expression.toString().split(" as ")[1],//别名作为Key tuples.get(i).get(expression));//获取结果 } list.add(map); } PageListMapResult pageListMapResult = new PageListMapResult(list, pageNo, pageSize, jpaQuery.fetchCount());//分页封装 return pageListMapResult; } } 支持的对象 queryDslContext package com.spark.bitrade.pagination; import com.querydsl.core.types.EntityPath; import com.querydsl.core.types.Expression; import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.Predicate; import java.util.ArrayList; import java.util.List; /** * @author rongyu * @description * @date 2018/3/7 13:10 */ public class QueryDslContext { private List<Expression> expressions; private List<EntityPath> entityPaths; private List<Predicate> predicates; private List<OrderSpecifier> orderSpecifiers; public QueryDslContext() { this.expressions = new ArrayList<>(); this.entityPaths = new ArrayList<>(); this.predicates = new ArrayList<>(); this.orderSpecifiers = new ArrayList<>(); } public List<Expression> getExpressions() { return expressions; } public void add(Expression expression) { expressions.add(expression); } public void add(EntityPath entityPath) { entityPaths.add(entityPath); } public void add(Predicate predicate) { predicates.add(predicate); } public void add(OrderSpecifier orderSpecifier) { orderSpecifiers.add(orderSpecifier); } public Expression[] expressionToArray() { return expressions.toArray(new Expression[expressions.size()]); } public EntityPath[] entityPathToArray() { return entityPaths.toArray(new EntityPath[entityPaths.size()]); } public Predicate[] predicatesToArray() { return predicates.toArray(new Predicate[predicates.size()]); } public OrderSpecifier[] orderSpecifiersToArray() { return orderSpecifiers.toArray(new OrderSpecifier[orderSpecifiers.size()]); } } 结果 对象 package com.spark.bitrade.pagination; import lombok.AllArgsConstructor; import lombok.Data; import java.io.Serializable; import java.util.List; import java.util.Map; /** * @author rongyu * @description * @date 2018/2/28 15:48 */ @AllArgsConstructor @Data public class PageListMapResult implements Serializable { private List<Map<String,Object>> list; private int pageNo; private int pageSize; private Long totalNumber; } 这是调用 =================================================自定义字段灵活条件分页查询方式============================== @GetMapping("withdraw-records/page-query/test") public MessageResult pageQueryTest( @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(value = "status", required = false) WithdrawStatus status) { QueryDslContext queryDslContext = new QueryDslContext(); //查询字段 queryDslContext.add(QWithdrawRecord.withdrawRecord.id.as("id")); queryDslContext.add(QWithdrawRecord.withdrawRecord.fee.as("fee")); queryDslContext.add(QWithdrawRecord.withdrawRecord.arrivedAmount.as("arrivedAmount")); queryDslContext.add(QWithdrawRecord.withdrawRecord.transactionNumber.as("transactionNumber")); queryDslContext.add(QWithdrawRecord.withdrawRecord.createTime.as("createTime")); queryDslContext.add(QWithdrawRecord.withdrawRecord.address.as("address")); queryDslContext.add(QWithdrawRecord.withdrawRecord.remark.as("remark")); queryDslContext.add(QWithdrawRecord.withdrawRecord.status.as("status")); //查询表 queryDslContext.add(QWithdrawRecord.withdrawRecord); queryDslContext.add(QMember.member); //查询条件 queryDslContext.add(QWithdrawRecord.withdrawRecord.memberId.eq(QMember.member.id)); if (status != null) queryDslContext.add(withdrawRecord.status.eq(status)); //排序 queryDslContext.add(QWithdrawRecord.withdrawRecord.id.desc()); PageListMapResult pageListMapResult = withdrawRecordService.queryDslForPageListResultTest(queryDslContext, pageNo, pageSize); return success(pageListMapResult); } =================================================灵活条件分页查询方式============================== //条件 List<Predicate> predicateList = new ArrayList<>(); predicateList.add(QAdvertise.advertise.member.id.eq(member.getId())); if (status != null) predicateList.add(QAdvertise.advertise.status.eq(status)); if (advertiseType != null) predicateList.add(QAdvertise.advertise.advertiseType.eq(advertiseType)); //排序 List<OrderSpecifier> orderSpecifierList = new ArrayList<>(); orderSpecifierList.add(QAdvertise.advertise.id.desc()); //查询 PageResult<Advertise> advertisePageResult = advertiseService.queryDsl(pageNo, pageSize, predicateList, QAdvertise.advertise, orderSpecifierList);

优秀的个人博客,低调大师

应用程序内部任意界面退出程序

创建工具类如下: package com.example.hxd.gittest; import android.app.Activity; import java.util.ArrayList; import java.util.List; /** * 统一退出程序的操作 */ class ActivitySetting { //创建集合存储打开的Activity static List<Activity> activityList = new ArrayList<>(); //添加打开的Activity到集合 static void addActivity(Activity activity) { activityList.add(activity); } //移除集合内部的Activity static void removeActivity(Activity activity) { activityList.remove(activity); } //关闭所有的Activity static void finishAllActivity() { for (Activity activity : activityList) { if (!activity.isFinishing()) { activity.finish(); //杀死当前应用进程 android.os.Process.killProcess(android.os.Process.myPid()); } } } } 在BaseActivity内部添加如下代码: package com.example.hxd.gittest; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_base); //添加当前操作的Activity到集合内部 ActivitySetting.addActivity(this); } @Override protected void onDestroy() { super.onDestroy(); //移除无用的Activity ActivitySetting.removeActivity(this); } } 具体Activity内部代码如下: btnSecond.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //点击按钮退出程序,杀死进程 ActivitySetting.finishAllActivity(); } });

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册