編輯:關於Android編程
這些天,項目裡加了一個功能效果,場景是: 假如有一個家居圖片,圖片裡,有各樣的家居用品: 桌子,毛巾,花瓶等等,需要在指定的商品處添加標記,方便用戶直接看到商品,點擊該標記,可以進入到商品詳情頁 。實現的效果圖如下:
要實現如上效果,有兩個思路。
思路1,通過addView,在容器(如FrameLayout)的特定位置,添加標記組件,同事在將ImageView頁添加進容器中,保證容器的大小和ImageView的大小相同,這樣可以確認標記點的位置不會出現錯差。
思路2,通過繪制Bitmap,將背景圖片和標記點繪制成同一張圖片。
比較兩種方法,思路2有些不太妥的地方,1是不好實現標記圖標的點擊事件;2是不太容易擴展,比如標記點不僅僅是一個圖片,而是一個彈框組件,有圖有文。 所以,考慮再三後,決定選擇第一種實現方式。
1. 自定義布局,包含放置標記圖標的容器及顯示底部圖片的ImageView。
<framelayout android:layout_height="wrap_content" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"><framelayout android:id="@+id/layouPoints" android:layout_gravity="center" android:layout_height="wrap_content" android:layout_width="match_parent"> </framelayout> </framelayout>
import android.content.Context; import android.graphics.drawable.AnimationDrawable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Toast; import com.bumptech.glide.Glide; import com.lnyp.imgdots.R; import com.lnyp.imgdots.bean.PointSimple; import java.util.ArrayList; public class ImageLayout extends FrameLayout implements View.OnClickListener { ArrayList來看看ImageLayout源碼,裡面有兩個重要的方法:points; FrameLayout layouPoints; ImageView imgBg; Context mContext; public ImageLayout(Context context) { this(context, null); } public ImageLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ImageLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context, attrs); } private void initView(Context context, AttributeSet attrs) { mContext = context; View imgPointLayout = inflate(context, R.layout.layout_imgview_point, this); imgBg = (ImageView) imgPointLayout.findViewById(R.id.imgBg); layouPoints = (FrameLayout) imgPointLayout.findViewById(R.id.layouPoints); } public void setImgBg(int width, int height, String imgUrl) { ViewGroup.LayoutParams lp = imgBg.getLayoutParams(); lp.width = width; lp.height = height; imgBg.setLayoutParams(lp); ViewGroup.LayoutParams lp1 = layouPoints.getLayoutParams(); lp1.width = width; lp1.height = height; layouPoints.setLayoutParams(lp1); Glide.with(mContext).load(imgUrl).asBitmap().into(imgBg); addPoints(width, height); } public void setPoints(ArrayList points) { this.points = points; } private void addPoints(int width, int height) { layouPoints.removeAllViews(); for (int i = 0; i < points.size(); i++) { double width_scale = points.get(i).width_scale; double height_scale = points.get(i).height_scale; LinearLayout view = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.layout_img_point, this, false); ImageView imageView = (ImageView) view.findViewById(R.id.imgPoint); imageView.setTag(i); AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable(); animationDrawable.start(); LayoutParams layoutParams = (LayoutParams) view.getLayoutParams(); layoutParams.leftMargin = (int) (width * width_scale); layoutParams.topMargin = (int) (height * height_scale); imageView.setOnClickListener(this); layouPoints.addView(view, layoutParams); } } @Override public void onClick(View view) { int pos = (int) view.getTag(); Toast.makeText(getContext(), "pos : " + pos, Toast.LENGTH_SHORT).show(); } }
·public void setImgBg(int width, int height, String imgUrl) 該方法主要根據圖片的大小,設置標記圖容器的大小,然後加載背景圖。
·private void addPoints(int width, int height) 該方法主要向記圖容器中添加標記圖。
3.PointSimple.java
public class PointSimple { // 標記點相對於橫向的寬度的比例 public double width_scale; // 標記點相對於橫向的高度的比例 public double height_scale; }4. 添加背景圖和標記圖
4.1 首先,准備一些測試數據
private void initData() { imgSimples = new ArrayList<>(); ImgSimple imgSimple1 = new ImgSimple(); imgSimple1.url = "http://o79w6dswy.bkt.clouddn.com/img5.png"; imgSimple1.scale = 1.6f; ArrayListpointSimples = new ArrayList<>(); PointSimple pointSimple1 = new PointSimple(); pointSimple1.width_scale = 0.36f; pointSimple1.height_scale = 0.75f; PointSimple pointSimple2 = new PointSimple(); pointSimple2.width_scale = 0.64f; pointSimple2.height_scale = 0.5f; PointSimple pointSimple3 = new PointSimple(); pointSimple3.width_scale = 0.276f; pointSimple3.height_scale = 0.764f; PointSimple pointSimple4 = new PointSimple(); pointSimple4.width_scale = 0.638f; pointSimple4.height_scale = 0.74f; PointSimple pointSimple5 = new PointSimple(); pointSimple5.width_scale = 0.796f; pointSimple5.height_scale = 0.526f; PointSimple pointSimple6 = new PointSimple(); pointSimple6.width_scale = 0.486f; pointSimple6.height_scale = 0.364f; pointSimples.add(pointSimple1); pointSimples.add(pointSimple2); pointSimples.add(pointSimple3); pointSimples.add(pointSimple4); pointSimples.add(pointSimple5); pointSimples.add(pointSimple6); imgSimple1.pointSimples = pointSimples; ImgSimple imgSimple2 = new ImgSimple(); imgSimple2.url = "http://o79w6dswy.bkt.clouddn.com/img3.png"; imgSimple2.scale = 1.6f; ArrayList pointSimples2 = new ArrayList<>(); PointSimple pointSimple7 = new PointSimple(); pointSimple7.width_scale = 0.36f; pointSimple7.height_scale = 0.75f; PointSimple pointSimple8 = new PointSimple(); pointSimple8.width_scale = 0.64f; pointSimple8.height_scale = 0.5f; PointSimple pointSimple9 = new PointSimple(); pointSimple9.width_scale = 0.276f; pointSimple9.height_scale = 0.764f; pointSimples2.add(pointSimple7); pointSimples2.add(pointSimple8); pointSimples2.add(pointSimple9); imgSimple2.pointSimples = pointSimples2; ImgSimple imgSimple3 = new ImgSimple(); imgSimple3.url = "http://o79w6dswy.bkt.clouddn.com/421428.jpg"; imgSimple3.scale = 0.75f; ArrayList pointSimples3 = new ArrayList<>(); PointSimple pointSimple11 = new PointSimple(); pointSimple11.width_scale = 0.1f; pointSimple11.height_scale = 0.3f; PointSimple pointSimple12 = new PointSimple(); pointSimple12.width_scale = 0.3f; pointSimple12.height_scale = 0.5f; PointSimple pointSimple13 = new PointSimple(); pointSimple13.width_scale = 0.5f; pointSimple13.height_scale = 0.8f; pointSimples3.add(pointSimple11); pointSimples3.add(pointSimple12); pointSimples3.add(pointSimple13); imgSimple3.pointSimples = pointSimples3; imgSimples.add(imgSimple1); imgSimples.add(imgSimple2); imgSimples.add(imgSimple3); }
import android.app.Activity; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import com.lnyp.imgdots.R; import com.lnyp.imgdots.bean.ImgSimple; import com.lnyp.imgdots.bean.PointSimple; import com.lnyp.imgdots.view.ImageLayout; import java.util.ArrayList; import java.util.List; public class ImgBrowsePagerAdapter extends PagerAdapter { List4.3 適配器的布局文件layout_img_browse.xml,其中包含了上方自定義的組件ImageLayoutimgSimples; List views; Activity mContext; private int width; public ImgBrowsePagerAdapter(Activity context, List imgSimples) { this.mContext = context; this.imgSimples = imgSimples; this.views = new ArrayList<>(); DisplayMetrics dm = new DisplayMetrics(); context.getWindowManager().getDefaultDisplay().getMetrics(dm); width = dm.widthPixels; } @Override public int getCount() { // 獲得size return imgSimples.size(); } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public void destroyItem(ViewGroup container, int position, Object object) { ((ViewPager) container).removeView((View) object); } @Override public Object instantiateItem(ViewGroup container, int position) { LinearLayout view = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.layout_img_browse, null); ImageLayout layoutContent = (ImageLayout) view.findViewById(R.id.layoutContent); try { String imgUrl = imgSimples.get(position).url; float scale = imgSimples.get(position).scale; ArrayList pointSimples = imgSimples.get(position).pointSimples; layoutContent.setPoints(pointSimples); int height = (int) (width * scale); layoutContent.setImgBg(width, height, imgUrl); } catch (Exception e) { e.printStackTrace(); } ((ViewPager) container).addView(view); return view; } }
此處,稍微講下ImgBrowsePagerAdapter的instantiateItem(ViewGroup container, int position)方法,在該方法中,我們根據屏幕的寬度,對圖片進行等比縮放,計算出了縮放後圖片的大小(height和width), 該height和width也就是我們將要添加標記物所在的容器的大小。
通過加載了布局文件,獲取ImageLayout對象; 然後,有了這個對象,及計算出的height和width,我們就可以動態的添加背景圖及標記物的位置。
因為圖片是經過等比縮放的,而標記物的位置是相對於圖片的,所以在相同大小的容器添加標記物,它的位置不會出現偏差。
通過以上幾步,便可以實現前面動態圖中的功能效果了。
如有疑問或建議,歡迎進QQ群討論:487786925( Android研發村 )
項目github地址:https://github.com/zuiwuyuan/ImgDots
效果圖思路:就是先設置Gridlayout的行列數,然後往裡面放置一定數目的自定義日歷按鈕控件,最後實現日歷邏輯就可以了。步驟:第一步:自定義日歷控件(初步)第二步:實現
當然選類似微信的剪裁咯,為什麼?請看下文分析眾所周知頭像剪裁上傳是絕大部分APP必備的功能之一,但是剪裁的模式有2種交互形式,第一種是采用系統自帶的剪裁功能,我個人是比較
DRM In this document Overview Android DRM FrameworkWidevine DR
轉載須注明。 一個博士同學,找到我,想我合伙,幫助他解決移動端產品。他給我描述了他的想法,搜布,用圖像識別的算法去搜索布匹,然後推薦,然後關聯商家。這麼一個