編輯:關於Android編程
0.首先,先給出一張效果gif圖。

1.貝塞爾曲線原理及相關公式參考:http://www.jianshu.com/p/c0d7ad796cee 作者:許方鎮。
2.原理:計算被點擊 view、購物車view 以及他們所在父容器相對於屏幕的坐標。
3.在呗點擊View坐標位置 父容器通過addView 增加需要完成動畫的imgview。
4.自定義估值器 通過二次貝塞爾曲線公式(2個數據點,一個控制點)完成拋物線路徑上的點xy坐標計算。
5.利用屬性動畫 +自定義估值器 完成imgview在父容器內部的拋物線動畫。
6.先給布局,其中包含一個ListView、 一個ImageView 、需要用到的父容器。
public class ItemAdapter extends BaseAdapter implements View.OnClickListener {
List data = new ArrayList<>();
Context mContext;
public ItemAdapter(Context context) {
mContext = context;
for (int i = 0; i < 30; i++) {
data.add("item+" + i);
}
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.item, parent, false);
convertView.setTag(new ViewH(convertView));
}
ViewH holder = (ViewH) convertView.getTag();
holder.tv.setText(data.get(position));
holder.img.setOnClickListener(this);
return convertView;
}
@Override
public void onClick(View v) {
if (mListener != null) {
mListener.add(v);
}
}
private AddClickListener mListener;
public void setListener(AddClickListener listener) {
mListener = listener;
}
public interface AddClickListener {
void add(View v);
}
public static class ViewH {
private ImageView img;
private TextView tv;
public ViewH(View view) {
img = ((ImageView) view.findViewById(R.id.item_img));
tv = ((TextView) view.findViewById(R.id.item_text));
}
}
}
9.其中自定義MoveImageView僅僅是增加了一個set方法方便屬性動畫 update時調用。
public class MoveImageView extends ImageView {
public MoveImageView(Context context) {
super(context);
}
public void setMPointF(PointF pointF) {
setX(pointF.x);
setY(pointF.y);
}
}
public class MainActivity extends AppCompatActivity implements ItemAdapter.AddClickListener, Animator.AnimatorListener {
private ImageView shopImg;//購物車 IMG
private RelativeLayout container;//ListView 購物車View的父布局
private ListView itemLv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViews();
initViews();
}
private void initViews() {
ItemAdapter adapter = new ItemAdapter(this);
//當前Activity實現 adapter內部 點擊的回調
adapter.setListener(this);
itemLv.setAdapter(adapter);
}
/**
* ListView + 點擊回調方法
*/
@Override
public void add(View addV) {
int[] childCoordinate = new int[2];
int[] parentCoordinate = new int[2];
int[] shopCoordinate = new int[2];
//1.分別獲取被點擊View、父布局、購物車在屏幕上的坐標xy。
addV.getLocationInWindow(childCoordinate);
container.getLocationInWindow(parentCoordinate);
shopImg.getLocationInWindow(shopCoordinate);
//2.自定義ImageView 繼承ImageView
MoveImageView img = new MoveImageView(this);
img.setImageResource(R.mipmap.heart1);
//3.設置img在父布局中的坐標位置
img.setX(childCoordinate[0] - parentCoordinate[0]);
img.setY(childCoordinate[1] - parentCoordinate[1]);
//4.父布局添加該Img
container.addView(img);
//5.利用 二次貝塞爾曲線 需首先計算出 MoveImageView的2個數據點和一個控制點
PointF startP = new PointF();
PointF endP = new PointF();
PointF controlP = new PointF();
//開始的數據點坐標就是 addV的坐標
startP.x = childCoordinate[0] - parentCoordinate[0];
startP.y = childCoordinate[1] - parentCoordinate[1];
//結束的數據點坐標就是 shopImg的坐標
endP.x = shopCoordinate[0] - parentCoordinate[0];
endP.y = shopCoordinate[1] - parentCoordinate[1];
//控制點坐標 x等於 購物車x;y等於 addV的y
controlP.x = endP.x;
controlP.y = startP.y;
//啟動屬性動畫
ObjectAnimator animator = ObjectAnimator.ofObject(img, "mPointF",
new PointFTypeEvaluator(controlP), startP, endP);
animator.setDuration(1000);
animator.addListener(this);
animator.start();
}
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
//動畫結束後 父布局移除 img
Object target = ((ObjectAnimator) animation).getTarget();
container.removeView((View) target);
//shopImg 開始一個放大動畫
Animation scaleAnim = AnimationUtils.loadAnimation(this, R.anim.shop_scale);
shopImg.startAnimation(scaleAnim);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
/**
* 自定義估值器
*/
public class PointFTypeEvaluator implements TypeEvaluator {
/**
* 每個估值器對應一個屬性動畫,每個屬性動畫僅對應唯一一個控制點
*/
PointF control;
/**
* 估值器返回值
*/
PointF mPointF = new PointF();
public PointFTypeEvaluator(PointF control) {
this.control = control;
}
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
return getBezierPoint(startValue, endValue, control, fraction);
}
/**
* 二次貝塞爾曲線公式
*
* @param start 開始的數據點
* @param end 結束的數據點
* @param control 控制點
* @param t float 0-1
* @return 不同t對應的PointF
*/
private PointF getBezierPoint(PointF start, PointF end, PointF control, float t) {
mPointF.x = (1 - t) * (1 - t) * start.x + 2 * t * (1 - t) * control.x + t * t * end.x;
mPointF.y = (1 - t) * (1 - t) * start.y + 2 * t * (1 - t) * control.y + t * t * end.y;
return mPointF;
}
}
private void findViews() {
shopImg = (ImageView) findViewById(R.id.main_img);
container = (RelativeLayout) findViewById(R.id.main_container);
itemLv = (ListView) findViewById(R.id.main_lv);
}
}
Android apk增量升級
前言別看本文看上去很簡單,實際在實驗過程中遇到了很多問題,比如andorid studio下ndk編譯報錯,而本文呈現給大家的都是最終可行的方法.所需資源bzip2 bs
android OTA升級包制作
0.簽名java -Xmx2048m -jar out/host/linux-x86/framework/signapk.jar -w build/target/prod
Android UI之自定義——類似iOS的Tabbar
Android UI之自定義——類似iOS的TabbarTabbar最早出現在iOS,iOS中的TabBarController實現了
Android內存洩漏查找和解決
一.內存洩漏概念1.什麼是內存洩漏?用動態存儲分配函數動態開辟的空間,在使用完畢後未釋放,結果導致一直占據該內存單元。直到程序結束。即所謂的內存洩漏。其實說白了就是該內存